@acahet/playwright-rules 0.0.2
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 +50 -0
- package/dist/base/index.d.ts +15 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +16 -0
- package/dist/base/index.js.map +1 -0
- package/dist/eslint/index.d.ts +87 -0
- package/dist/eslint/index.d.ts.map +1 -0
- package/dist/eslint/index.js +82 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/rules/no-brittle-selectors.d.ts +4 -0
- package/dist/eslint/rules/no-brittle-selectors.d.ts.map +1 -0
- package/dist/eslint/rules/no-brittle-selectors.js +47 -0
- package/dist/eslint/rules/no-brittle-selectors.js.map +1 -0
- package/dist/eslint/rules/no-focused-tests.d.ts +4 -0
- package/dist/eslint/rules/no-focused-tests.d.ts.map +1 -0
- package/dist/eslint/rules/no-focused-tests.js +58 -0
- package/dist/eslint/rules/no-focused-tests.js.map +1 -0
- package/dist/eslint/rules/no-page-pause.d.ts +4 -0
- package/dist/eslint/rules/no-page-pause.d.ts.map +1 -0
- package/dist/eslint/rules/no-page-pause.js +32 -0
- package/dist/eslint/rules/no-page-pause.js.map +1 -0
- package/dist/eslint/rules/no-wait-for-timeout.d.ts +4 -0
- package/dist/eslint/rules/no-wait-for-timeout.d.ts.map +1 -0
- package/dist/eslint/rules/no-wait-for-timeout.js +29 -0
- package/dist/eslint/rules/no-wait-for-timeout.js.map +1 -0
- package/dist/eslint/rules/prefer-web-first-assertions.d.ts +4 -0
- package/dist/eslint/rules/prefer-web-first-assertions.d.ts.map +1 -0
- package/dist/eslint/rules/prefer-web-first-assertions.js +78 -0
- package/dist/eslint/rules/prefer-web-first-assertions.js.map +1 -0
- package/dist/eslint/rules/require-test-description.d.ts +4 -0
- package/dist/eslint/rules/require-test-description.d.ts.map +1 -0
- package/dist/eslint/rules/require-test-description.js +129 -0
- package/dist/eslint/rules/require-test-description.js.map +1 -0
- package/dist/eslint/types.d.ts +17 -0
- package/dist/eslint/types.d.ts.map +1 -0
- package/dist/eslint/types.js +3 -0
- package/dist/eslint/types.js.map +1 -0
- package/dist/eslint/utils/ast.d.ts +10 -0
- package/dist/eslint/utils/ast.d.ts.map +1 -0
- package/dist/eslint/utils/ast.js +54 -0
- package/dist/eslint/utils/ast.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/playwright/index.d.ts +7 -0
- package/dist/playwright/index.d.ts.map +1 -0
- package/dist/playwright/index.js +23 -0
- package/dist/playwright/index.js.map +1 -0
- package/package.json +86 -0
- package/src/tsconfig/base.json +21 -0
- package/src/tsconfig/strict.json +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# @acahet/pw-standard
|
|
2
|
+
|
|
3
|
+
Shared Playwright standards package:
|
|
4
|
+
|
|
5
|
+
- ESLint plugin and custom rules
|
|
6
|
+
- base classes/fixtures entrypoint
|
|
7
|
+
- shared tsconfig presets
|
|
8
|
+
- compatibility bridge export for Playwright config (`@acahet/pw-standard/playwright`)
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm i -D @acahet/pw-standard
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
### ESLint plugin
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import plugin from '@acahet/pw-standard/eslint';
|
|
22
|
+
|
|
23
|
+
export default [
|
|
24
|
+
{
|
|
25
|
+
plugins: {
|
|
26
|
+
'playwright-standards': plugin,
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
'playwright-standards/no-wait-for-timeout': 'error',
|
|
30
|
+
'playwright-standards/no-brittle-selectors': 'error',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### TSConfig preset
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"extends": "@acahet/pw-standard/tsconfig/base"
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Playwright config compatibility export
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import * as configPreset from '@acahet/pw-standard/playwright';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
New projects should import Playwright config presets from `@acahet/playwright-config` directly.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @acahet/pw-standard/base
|
|
3
|
+
*
|
|
4
|
+
* Shared base classes and fixtures for Playwright test suites.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
*
|
|
8
|
+
* import { BasePage } from '@acahet/pw-standard/base';
|
|
9
|
+
*
|
|
10
|
+
* export class LoginPage extends BasePage {
|
|
11
|
+
* async goto() { await this.page.goto('/login'); }
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/base/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @acahet/pw-standard/base
|
|
4
|
+
*
|
|
5
|
+
* Shared base classes and fixtures for Playwright test suites.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
*
|
|
9
|
+
* import { BasePage } from '@acahet/pw-standard/base';
|
|
10
|
+
*
|
|
11
|
+
* export class LoginPage extends BasePage {
|
|
12
|
+
* async goto() { await this.page.goto('/login'); }
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/base/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { RuleMap, ConfigRules } from './types';
|
|
2
|
+
declare const rules: RuleMap;
|
|
3
|
+
declare const configs: {
|
|
4
|
+
/**
|
|
5
|
+
* `recommended` — all recommended rules as errors.
|
|
6
|
+
* Best for CI enforcement.
|
|
7
|
+
*/
|
|
8
|
+
recommended: {
|
|
9
|
+
plugins: string[];
|
|
10
|
+
parserOptions: {
|
|
11
|
+
ecmaVersion: number;
|
|
12
|
+
sourceType: "module";
|
|
13
|
+
};
|
|
14
|
+
rules: ConfigRules;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* `strict` — all rules (including non-recommended) as errors.
|
|
18
|
+
*/
|
|
19
|
+
strict: {
|
|
20
|
+
plugins: string[];
|
|
21
|
+
parserOptions: {
|
|
22
|
+
ecmaVersion: number;
|
|
23
|
+
sourceType: "module";
|
|
24
|
+
};
|
|
25
|
+
rules: ConfigRules;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* `warn` — all recommended rules as warnings.
|
|
29
|
+
* Useful when adopting the plugin incrementally.
|
|
30
|
+
*/
|
|
31
|
+
warn: {
|
|
32
|
+
plugins: string[];
|
|
33
|
+
parserOptions: {
|
|
34
|
+
ecmaVersion: number;
|
|
35
|
+
sourceType: "module";
|
|
36
|
+
};
|
|
37
|
+
rules: ConfigRules;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
declare const plugin: {
|
|
41
|
+
meta: {
|
|
42
|
+
name: string;
|
|
43
|
+
version: string;
|
|
44
|
+
};
|
|
45
|
+
rules: RuleMap;
|
|
46
|
+
configs: {
|
|
47
|
+
/**
|
|
48
|
+
* `recommended` — all recommended rules as errors.
|
|
49
|
+
* Best for CI enforcement.
|
|
50
|
+
*/
|
|
51
|
+
recommended: {
|
|
52
|
+
plugins: string[];
|
|
53
|
+
parserOptions: {
|
|
54
|
+
ecmaVersion: number;
|
|
55
|
+
sourceType: "module";
|
|
56
|
+
};
|
|
57
|
+
rules: ConfigRules;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* `strict` — all rules (including non-recommended) as errors.
|
|
61
|
+
*/
|
|
62
|
+
strict: {
|
|
63
|
+
plugins: string[];
|
|
64
|
+
parserOptions: {
|
|
65
|
+
ecmaVersion: number;
|
|
66
|
+
sourceType: "module";
|
|
67
|
+
};
|
|
68
|
+
rules: ConfigRules;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* `warn` — all recommended rules as warnings.
|
|
72
|
+
* Useful when adopting the plugin incrementally.
|
|
73
|
+
*/
|
|
74
|
+
warn: {
|
|
75
|
+
plugins: string[];
|
|
76
|
+
parserOptions: {
|
|
77
|
+
ecmaVersion: number;
|
|
78
|
+
sourceType: "module";
|
|
79
|
+
};
|
|
80
|
+
rules: ConfigRules;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
export default plugin;
|
|
85
|
+
export { rules, configs };
|
|
86
|
+
export type { RuleMap, ConfigRules };
|
|
87
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAW/C,QAAA,MAAM,KAAK,EAAE,OAOZ,CAAC;AAuBF,QAAA,MAAM,OAAO;IACZ;;;OAGG;;;;;;;;;IAOH;;OAEG;;;;;;;;;IAUH;;;OAGG;;;;;;;;;CAMH,CAAC;AAIF,QAAA,MAAM,MAAM;;;;;;;QAnCX;;;WAGG;;;;;;;;;QAOH;;WAEG;;;;;;;;;QAUH;;;WAGG;;;;;;;;;;CAiBH,CAAC;AAEF,eAAe,MAAM,CAAC;AAGtB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC1B,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
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.configs = exports.rules = void 0;
|
|
7
|
+
const no_wait_for_timeout_1 = __importDefault(require("./rules/no-wait-for-timeout"));
|
|
8
|
+
const no_brittle_selectors_1 = __importDefault(require("./rules/no-brittle-selectors"));
|
|
9
|
+
const require_test_description_1 = __importDefault(require("./rules/require-test-description"));
|
|
10
|
+
const no_page_pause_1 = __importDefault(require("./rules/no-page-pause"));
|
|
11
|
+
const no_focused_tests_1 = __importDefault(require("./rules/no-focused-tests"));
|
|
12
|
+
const prefer_web_first_assertions_1 = __importDefault(require("./rules/prefer-web-first-assertions"));
|
|
13
|
+
// ─── Rule registry ────────────────────────────────────────────────────────────
|
|
14
|
+
// Add new rules here — they are automatically picked up by all configs below.
|
|
15
|
+
const rules = {
|
|
16
|
+
'no-wait-for-timeout': no_wait_for_timeout_1.default,
|
|
17
|
+
'no-brittle-selectors': no_brittle_selectors_1.default,
|
|
18
|
+
'require-test-description': require_test_description_1.default,
|
|
19
|
+
'no-page-pause': no_page_pause_1.default,
|
|
20
|
+
'no-focused-tests': no_focused_tests_1.default,
|
|
21
|
+
'prefer-web-first-assertions': prefer_web_first_assertions_1.default,
|
|
22
|
+
};
|
|
23
|
+
exports.rules = rules;
|
|
24
|
+
// ─── Shared parser options ────────────────────────────────────────────────────
|
|
25
|
+
const PARSER_OPTIONS = {
|
|
26
|
+
ecmaVersion: 2020,
|
|
27
|
+
sourceType: 'module',
|
|
28
|
+
};
|
|
29
|
+
// ─── Helper: prefix all rule keys with the plugin name ───────────────────────
|
|
30
|
+
function prefixedRules(severity) {
|
|
31
|
+
return Object.keys(rules).reduce((acc, key) => {
|
|
32
|
+
const meta = rules[key].meta;
|
|
33
|
+
if (meta.docs?.recommended) {
|
|
34
|
+
acc[`playwright-standards/${key}`] = severity;
|
|
35
|
+
}
|
|
36
|
+
return acc;
|
|
37
|
+
}, {});
|
|
38
|
+
}
|
|
39
|
+
// ─── Configs ──────────────────────────────────────────────────────────────────
|
|
40
|
+
const configs = {
|
|
41
|
+
/**
|
|
42
|
+
* `recommended` — all recommended rules as errors.
|
|
43
|
+
* Best for CI enforcement.
|
|
44
|
+
*/
|
|
45
|
+
recommended: {
|
|
46
|
+
plugins: ['playwright-standards'],
|
|
47
|
+
parserOptions: PARSER_OPTIONS,
|
|
48
|
+
rules: prefixedRules('error'),
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* `strict` — all rules (including non-recommended) as errors.
|
|
52
|
+
*/
|
|
53
|
+
strict: {
|
|
54
|
+
plugins: ['playwright-standards'],
|
|
55
|
+
parserOptions: PARSER_OPTIONS,
|
|
56
|
+
rules: Object.keys(rules).reduce((acc, key) => {
|
|
57
|
+
acc[`playwright-standards/${key}`] = 'error';
|
|
58
|
+
return acc;
|
|
59
|
+
}, {}),
|
|
60
|
+
},
|
|
61
|
+
/**
|
|
62
|
+
* `warn` — all recommended rules as warnings.
|
|
63
|
+
* Useful when adopting the plugin incrementally.
|
|
64
|
+
*/
|
|
65
|
+
warn: {
|
|
66
|
+
plugins: ['playwright-standards'],
|
|
67
|
+
parserOptions: PARSER_OPTIONS,
|
|
68
|
+
rules: prefixedRules('warn'),
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
exports.configs = configs;
|
|
72
|
+
// ─── Plugin export ────────────────────────────────────────────────────────────
|
|
73
|
+
const plugin = {
|
|
74
|
+
meta: {
|
|
75
|
+
name: '@acahet/pw-standard',
|
|
76
|
+
version: '1.0.0',
|
|
77
|
+
},
|
|
78
|
+
rules,
|
|
79
|
+
configs,
|
|
80
|
+
};
|
|
81
|
+
exports.default = plugin;
|
|
82
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/eslint/index.ts"],"names":[],"mappings":";;;;;;AACA,sFAA2D;AAC3D,wFAA8D;AAC9D,gGAAsE;AACtE,0EAAgD;AAChD,gFAAsD;AACtD,sGAA2E;AAE3E,iFAAiF;AACjF,8EAA8E;AAE9E,MAAM,KAAK,GAAY;IACtB,qBAAqB,EAAE,6BAAgB;IACvC,sBAAsB,EAAE,8BAAkB;IAC1C,0BAA0B,EAAE,kCAAsB;IAClD,eAAe,EAAE,uBAAW;IAC5B,kBAAkB,EAAE,0BAAc;IAClC,6BAA6B,EAAE,qCAAwB;CACvD,CAAC;AAuEO,sBAAK;AArEd,iFAAiF;AAEjF,MAAM,cAAc,GAAG;IACtB,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,QAAiB;CAC7B,CAAC;AAEF,gFAAgF;AAEhF,SAAS,aAAa,CAAC,QAA0B;IAChD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAc,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;YAC5B,GAAG,CAAC,wBAAwB,GAAG,EAAE,CAAC,GAAG,QAAQ,CAAC;QAC/C,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC,EAAE,EAAE,CAAC,CAAC;AACR,CAAC;AAED,iFAAiF;AAEjF,MAAM,OAAO,GAAG;IACf;;;OAGG;IACH,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,sBAAsB,CAAC;QACjC,aAAa,EAAE,cAAc;QAC7B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC;KAC7B;IAED;;OAEG;IACH,MAAM,EAAE;QACP,OAAO,EAAE,CAAC,sBAAsB,CAAC;QACjC,aAAa,EAAE,cAAc;QAC7B,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAc,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC1D,GAAG,CAAC,wBAAwB,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC;YAC7C,OAAO,GAAG,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC;KACN;IAED;;;OAGG;IACH,IAAI,EAAE;QACL,OAAO,EAAE,CAAC,sBAAsB,CAAC;QACjC,aAAa,EAAE,cAAc;QAC7B,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC;KAC5B;CACD,CAAC;AAgBc,0BAAO;AAdvB,iFAAiF;AAEjF,MAAM,MAAM,GAAG;IACd,IAAI,EAAE;QACL,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,OAAO;KAChB;IACD,KAAK;IACL,OAAO;CACP,CAAC;AAEF,kBAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-brittle-selectors.d.ts","sourceRoot":"","sources":["../../../src/eslint/rules/no-brittle-selectors.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAUtC,QAAA,MAAM,IAAI,EAAE,UAqCX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ast_1 = require("../utils/ast");
|
|
4
|
+
const LOCATOR_METHODS = new Set([
|
|
5
|
+
'locator',
|
|
6
|
+
'$',
|
|
7
|
+
'$$',
|
|
8
|
+
'waitForSelector',
|
|
9
|
+
'querySelector',
|
|
10
|
+
]);
|
|
11
|
+
const rule = {
|
|
12
|
+
meta: {
|
|
13
|
+
type: 'suggestion',
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Discourage brittle CSS / XPath selectors — prefer getByTestId, getByRole, getByLabel, etc.',
|
|
16
|
+
category: 'Best Practices',
|
|
17
|
+
recommended: true,
|
|
18
|
+
url: 'https://github.com/acahet-automation-org/playwright-standards/blob/main/docs/rules/no-brittle-selectors.md',
|
|
19
|
+
},
|
|
20
|
+
messages: {
|
|
21
|
+
brittleSelector: 'Brittle selector "{{selector}}". Prefer getByTestId(), getByRole(), getByLabel(), or getByText() instead.',
|
|
22
|
+
},
|
|
23
|
+
schema: [],
|
|
24
|
+
},
|
|
25
|
+
create(context) {
|
|
26
|
+
return {
|
|
27
|
+
CallExpression(node) {
|
|
28
|
+
const method = (0, ast_1.getMethodName)(node);
|
|
29
|
+
if (!method || !LOCATOR_METHODS.has(method))
|
|
30
|
+
return;
|
|
31
|
+
const firstArg = node.arguments[0];
|
|
32
|
+
if (!firstArg || firstArg.type !== 'Literal')
|
|
33
|
+
return;
|
|
34
|
+
const selector = String(firstArg.value);
|
|
35
|
+
if ((0, ast_1.isBrittleSelector)(selector)) {
|
|
36
|
+
context.report({
|
|
37
|
+
node: firstArg,
|
|
38
|
+
messageId: 'brittleSelector',
|
|
39
|
+
data: { selector },
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
exports.default = rule;
|
|
47
|
+
//# sourceMappingURL=no-brittle-selectors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-brittle-selectors.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-brittle-selectors.ts"],"names":[],"mappings":";;AAEA,sCAAgE;AAGhE,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC/B,SAAS;IACT,GAAG;IACH,IAAI;IACJ,iBAAiB;IACjB,eAAe;CACf,CAAC,CAAC;AAEH,MAAM,IAAI,GAAe;IACxB,IAAI,EAAE;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACL,WAAW,EACV,4FAA4F;YAC7F,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,4GAA4G;SACjH;QACD,QAAQ,EAAE;YACT,eAAe,EACd,2GAA2G;SAC5G;QACD,MAAM,EAAE,EAAE;KACV;IAED,MAAM,CAAC,OAAyB;QAC/B,OAAO;YACN,cAAc,CAAC,IAAoB;gBAClC,MAAM,MAAM,GAAG,IAAA,mBAAa,EAAC,IAAI,CAAC,CAAC;gBACnC,IAAI,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC;oBAAE,OAAO;gBAEpD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBACnC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS;oBAAE,OAAO;gBAErD,MAAM,QAAQ,GAAG,MAAM,CAAE,QAAoB,CAAC,KAAK,CAAC,CAAC;gBACrD,IAAI,IAAA,uBAAiB,EAAC,QAAQ,CAAC,EAAE,CAAC;oBACjC,OAAO,CAAC,MAAM,CAAC;wBACd,IAAI,EAAE,QAAQ;wBACd,SAAS,EAAE,iBAAiB;wBAC5B,IAAI,EAAE,EAAE,QAAQ,EAAE;qBAClB,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC;AAEF,kBAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-focused-tests.d.ts","sourceRoot":"","sources":["../../../src/eslint/rules/no-focused-tests.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKtC,QAAA,MAAM,IAAI,EAAE,UAmDX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const FOCUSED_METHODS = new Set(['only', 'skip']);
|
|
4
|
+
const TEST_DESCRIBE_OBJECTS = new Set(['test', 'it', 'describe']);
|
|
5
|
+
const rule = {
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Disallow test.only() / describe.only() — remove before committing',
|
|
10
|
+
category: 'Best Practices',
|
|
11
|
+
recommended: true,
|
|
12
|
+
url: 'https://github.com/acahet-automation-org/playwright-standards/blob/main/docs/rules/no-focused-tests.md',
|
|
13
|
+
},
|
|
14
|
+
messages: {
|
|
15
|
+
noOnly: '"{{parent}}.only()" found. Remove it before committing to avoid blocking the full test suite.',
|
|
16
|
+
noSkip: '"{{parent}}.skip()" found. Remove or resolve the skip before committing.',
|
|
17
|
+
},
|
|
18
|
+
schema: [
|
|
19
|
+
{
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
allowSkip: { type: 'boolean' },
|
|
23
|
+
},
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
create(context) {
|
|
29
|
+
const options = context.options[0] ?? {};
|
|
30
|
+
const allowSkip = options.allowSkip ?? false;
|
|
31
|
+
return {
|
|
32
|
+
CallExpression(node) {
|
|
33
|
+
if (node.callee.type !== 'MemberExpression')
|
|
34
|
+
return;
|
|
35
|
+
const callee = node.callee;
|
|
36
|
+
if (callee.object.type !== 'Identifier')
|
|
37
|
+
return;
|
|
38
|
+
const parentName = callee.object.name;
|
|
39
|
+
if (!TEST_DESCRIBE_OBJECTS.has(parentName))
|
|
40
|
+
return;
|
|
41
|
+
if (callee.property.type !== 'Identifier')
|
|
42
|
+
return;
|
|
43
|
+
const methodName = callee.property.name;
|
|
44
|
+
if (!FOCUSED_METHODS.has(methodName))
|
|
45
|
+
return;
|
|
46
|
+
if (methodName === 'skip' && allowSkip)
|
|
47
|
+
return;
|
|
48
|
+
context.report({
|
|
49
|
+
node,
|
|
50
|
+
messageId: methodName === 'only' ? 'noOnly' : 'noSkip',
|
|
51
|
+
data: { parent: parentName },
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
exports.default = rule;
|
|
58
|
+
//# sourceMappingURL=no-focused-tests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-focused-tests.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-focused-tests.ts"],"names":[],"mappings":";;AAIA,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAClD,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AAElE,MAAM,IAAI,GAAe;IACvB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,mEAAmE;YAChF,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,wGAAwG;SAC9G;QACD,QAAQ,EAAE;YACR,MAAM,EAAE,+FAA+F;YACvG,MAAM,EAAE,0EAA0E;SACnF;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;iBAC/B;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IAED,MAAM,CAAC,OAAyB;QAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,SAAS,GAAY,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;QAEtD,OAAO;YACL,cAAc,CAAC,IAAoB;gBACjC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAAE,OAAO;gBACpD,MAAM,MAAM,GAAG,IAAI,CAAC,MAA0B,CAAC;gBAE/C,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;oBAAE,OAAO;gBAChD,MAAM,UAAU,GAAI,MAAM,CAAC,MAAqB,CAAC,IAAI,CAAC;gBACtD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC;oBAAE,OAAO;gBAEnD,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAAE,OAAO;gBAClD,MAAM,UAAU,GAAI,MAAM,CAAC,QAAuB,CAAC,IAAI,CAAC;gBACxD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC;oBAAE,OAAO;gBAE7C,IAAI,UAAU,KAAK,MAAM,IAAI,SAAS;oBAAE,OAAO;gBAE/C,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI;oBACJ,SAAS,EAAE,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ;oBACtD,IAAI,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE;iBAC7B,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-page-pause.d.ts","sourceRoot":"","sources":["../../../src/eslint/rules/no-page-pause.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,QAAA,MAAM,IAAI,EAAE,UA8BX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const rule = {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'problem',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Disallow page.pause() — remove before committing',
|
|
8
|
+
category: 'Best Practices',
|
|
9
|
+
recommended: true,
|
|
10
|
+
url: 'https://github.com/acahet-automation-org/playwright-standards/blob/main/docs/rules/no-page-pause.md',
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
noPagePause: 'page.pause() is for local debugging only. Remove it before committing.',
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
},
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
CallExpression(node) {
|
|
20
|
+
if (node.callee.type !== 'MemberExpression')
|
|
21
|
+
return;
|
|
22
|
+
const callee = node.callee;
|
|
23
|
+
if (callee.property.type === 'Identifier' &&
|
|
24
|
+
callee.property.name === 'pause') {
|
|
25
|
+
context.report({ node, messageId: 'noPagePause' });
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
exports.default = rule;
|
|
32
|
+
//# sourceMappingURL=no-page-pause.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-page-pause.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-page-pause.ts"],"names":[],"mappings":";;AAIA,MAAM,IAAI,GAAe;IACxB,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EAAE,kDAAkD;YAC/D,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,qGAAqG;SAC1G;QACD,QAAQ,EAAE;YACT,WAAW,EACV,wEAAwE;SACzE;QACD,MAAM,EAAE,EAAE;KACV;IAED,MAAM,CAAC,OAAyB;QAC/B,OAAO;YACN,cAAc,CAAC,IAAoB;gBAClC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAAE,OAAO;gBACpD,MAAM,MAAM,GAAG,IAAI,CAAC,MAA0B,CAAC;gBAC/C,IACC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACpC,MAAM,CAAC,QAAuB,CAAC,IAAI,KAAK,OAAO,EAC/C,CAAC;oBACF,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;gBACpD,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC;AAEF,kBAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-wait-for-timeout.d.ts","sourceRoot":"","sources":["../../../src/eslint/rules/no-wait-for-timeout.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,QAAA,MAAM,IAAI,EAAE,UA0BX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ast_1 = require("../utils/ast");
|
|
4
|
+
const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow waitForTimeout() — use explicit wait conditions instead',
|
|
9
|
+
category: 'Best Practices',
|
|
10
|
+
recommended: true,
|
|
11
|
+
url: 'https://github.com/acahet-automation-org/playwright-standards/blob/main/docs/rules/no-wait-for-timeout.md',
|
|
12
|
+
},
|
|
13
|
+
messages: {
|
|
14
|
+
noWaitForTimeout: 'Avoid waitForTimeout(). Use waitFor(), waitForResponse(), or expect(...).toBeVisible() instead.',
|
|
15
|
+
},
|
|
16
|
+
schema: [],
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
return {
|
|
20
|
+
CallExpression(node) {
|
|
21
|
+
if ((0, ast_1.isWaitForTimeout)(node)) {
|
|
22
|
+
context.report({ node, messageId: 'noWaitForTimeout' });
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
exports.default = rule;
|
|
29
|
+
//# sourceMappingURL=no-wait-for-timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-wait-for-timeout.js","sourceRoot":"","sources":["../../../src/eslint/rules/no-wait-for-timeout.ts"],"names":[],"mappings":";;AAEA,sCAAgD;AAGhD,MAAM,IAAI,GAAe;IACxB,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACL,WAAW,EACV,kEAAkE;YACnE,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,2GAA2G;SAChH;QACD,QAAQ,EAAE;YACT,gBAAgB,EACf,iGAAiG;SAClG;QACD,MAAM,EAAE,EAAE;KACV;IAED,MAAM,CAAC,OAAyB;QAC/B,OAAO;YACN,cAAc,CAAC,IAAoB;gBAClC,IAAI,IAAA,sBAAgB,EAAC,IAAI,CAAC,EAAE,CAAC;oBAC5B,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBACzD,CAAC;YACF,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC;AAEF,kBAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-web-first-assertions.d.ts","sourceRoot":"","sources":["../../../src/eslint/rules/prefer-web-first-assertions.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AA4BtC,QAAA,MAAM,IAAI,EAAE,UAyDX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const EAGER_METHODS = new Set([
|
|
4
|
+
'innerText',
|
|
5
|
+
'textContent',
|
|
6
|
+
'getAttribute',
|
|
7
|
+
'isVisible',
|
|
8
|
+
'isHidden',
|
|
9
|
+
'isEnabled',
|
|
10
|
+
'isDisabled',
|
|
11
|
+
'isChecked',
|
|
12
|
+
'inputValue',
|
|
13
|
+
'innerHTML',
|
|
14
|
+
]);
|
|
15
|
+
const PREFERRED = {
|
|
16
|
+
innerText: 'toHaveText()',
|
|
17
|
+
textContent: 'toHaveText()',
|
|
18
|
+
getAttribute: 'toHaveAttribute()',
|
|
19
|
+
isVisible: 'toBeVisible()',
|
|
20
|
+
isHidden: 'toBeHidden()',
|
|
21
|
+
isEnabled: 'toBeEnabled()',
|
|
22
|
+
isDisabled: 'toBeDisabled()',
|
|
23
|
+
isChecked: 'toBeChecked()',
|
|
24
|
+
inputValue: 'toHaveValue()',
|
|
25
|
+
innerHTML: 'toContainText() or toHaveText()',
|
|
26
|
+
};
|
|
27
|
+
const rule = {
|
|
28
|
+
meta: {
|
|
29
|
+
type: 'suggestion',
|
|
30
|
+
docs: {
|
|
31
|
+
description: 'Prefer Playwright web-first assertions over awaited property calls',
|
|
32
|
+
category: 'Best Practices',
|
|
33
|
+
recommended: true,
|
|
34
|
+
url: 'https://github.com/acahet-automation-org/playwright-standards/blob/main/docs/rules/prefer-web-first-assertions.md',
|
|
35
|
+
},
|
|
36
|
+
messages: {
|
|
37
|
+
preferWebFirst: 'Avoid awaiting "{{method}}()" inside expect(). Use the web-first assertion "{{preferred}}" instead — it auto-retries.',
|
|
38
|
+
},
|
|
39
|
+
schema: [],
|
|
40
|
+
},
|
|
41
|
+
create(context) {
|
|
42
|
+
const sourceCode = context.sourceCode;
|
|
43
|
+
return {
|
|
44
|
+
'CallExpression > AwaitExpression > CallExpression'(node) {
|
|
45
|
+
if (node.callee.type !== 'MemberExpression')
|
|
46
|
+
return;
|
|
47
|
+
const prop = node.callee.property;
|
|
48
|
+
if (prop.type !== 'Identifier')
|
|
49
|
+
return;
|
|
50
|
+
const method = prop.name;
|
|
51
|
+
if (!EAGER_METHODS.has(method))
|
|
52
|
+
return;
|
|
53
|
+
const ancestors = sourceCode.getAncestors(node);
|
|
54
|
+
const awaitExpr = ancestors[ancestors.length - 1];
|
|
55
|
+
if (!awaitExpr || awaitExpr.type !== 'AwaitExpression')
|
|
56
|
+
return;
|
|
57
|
+
const outerCall = ancestors[ancestors.length - 2];
|
|
58
|
+
if (!outerCall ||
|
|
59
|
+
outerCall.type !== 'CallExpression' ||
|
|
60
|
+
outerCall.callee.type !==
|
|
61
|
+
'Identifier' ||
|
|
62
|
+
outerCall.callee
|
|
63
|
+
.name !== 'expect')
|
|
64
|
+
return;
|
|
65
|
+
context.report({
|
|
66
|
+
node,
|
|
67
|
+
messageId: 'preferWebFirst',
|
|
68
|
+
data: {
|
|
69
|
+
method,
|
|
70
|
+
preferred: PREFERRED[method] ?? 'a web-first assertion',
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
exports.default = rule;
|
|
78
|
+
//# sourceMappingURL=prefer-web-first-assertions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefer-web-first-assertions.js","sourceRoot":"","sources":["../../../src/eslint/rules/prefer-web-first-assertions.ts"],"names":[],"mappings":";;AAIA,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC7B,WAAW;IACX,aAAa;IACb,cAAc;IACd,WAAW;IACX,UAAU;IACV,WAAW;IACX,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,WAAW;CACX,CAAC,CAAC;AAEH,MAAM,SAAS,GAA2B;IACzC,SAAS,EAAE,cAAc;IACzB,WAAW,EAAE,cAAc;IAC3B,YAAY,EAAE,mBAAmB;IACjC,SAAS,EAAE,eAAe;IAC1B,QAAQ,EAAE,cAAc;IACxB,SAAS,EAAE,eAAe;IAC1B,UAAU,EAAE,gBAAgB;IAC5B,SAAS,EAAE,eAAe;IAC1B,UAAU,EAAE,eAAe;IAC3B,SAAS,EAAE,iCAAiC;CAC5C,CAAC;AAEF,MAAM,IAAI,GAAe;IACxB,IAAI,EAAE;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACL,WAAW,EACV,oEAAoE;YACrE,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,mHAAmH;SACxH;QACD,QAAQ,EAAE;YACT,cAAc,EACb,uHAAuH;SACxH;QACD,MAAM,EAAE,EAAE;KACV;IAED,MAAM,CAAC,OAAyB;QAC/B,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QAEtC,OAAO;YACN,mDAAmD,CAClD,IAAoB;gBAEpB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAAE,OAAO;gBACpD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY;oBAAE,OAAO;gBAEvC,MAAM,MAAM,GAAI,IAAmB,CAAC,IAAI,CAAC;gBACzC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;oBAAE,OAAO;gBAEvC,MAAM,SAAS,GAAG,UAAU,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;gBAChD,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAClD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,iBAAiB;oBAAE,OAAO;gBAE/D,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBAClD,IACC,CAAC,SAAS;oBACV,SAAS,CAAC,IAAI,KAAK,gBAAgB;oBAClC,SAA4B,CAAC,MAAM,CAAC,IAAI;wBACxC,YAAY;oBACX,SAA4B,CAAC,MAAqB;yBAClD,IAAI,KAAK,QAAQ;oBAEnB,OAAO;gBAER,OAAO,CAAC,MAAM,CAAC;oBACd,IAAI;oBACJ,SAAS,EAAE,gBAAgB;oBAC3B,IAAI,EAAE;wBACL,MAAM;wBACN,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI,uBAAuB;qBACvD;iBACD,CAAC,CAAC;YACJ,CAAC;SACD,CAAC;IACH,CAAC;CACD,CAAC;AAEF,kBAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-test-description.d.ts","sourceRoot":"","sources":["../../../src/eslint/rules/require-test-description.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAsBtC,QAAA,MAAM,IAAI,EAAE,UAoIX,CAAC;AAEF,eAAe,IAAI,CAAC"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const TEST_FUNCTIONS = new Set(['test', 'it']);
|
|
4
|
+
const VAGUE_PATTERNS = [
|
|
5
|
+
/^test\s*\d*$/i,
|
|
6
|
+
/^it\s*\d*$/i,
|
|
7
|
+
/^spec\s*\d*$/i,
|
|
8
|
+
/^(todo|fixme|wip)$/i,
|
|
9
|
+
/^\d+$/,
|
|
10
|
+
];
|
|
11
|
+
const MIN_DESCRIPTION_LENGTH = 10;
|
|
12
|
+
const TEST_ID_AT_END_PATTERN = /\bnrt-\d+\s*$/i;
|
|
13
|
+
function getMeaningfulDescription(description) {
|
|
14
|
+
return description
|
|
15
|
+
.replace(TEST_ID_AT_END_PATTERN, '')
|
|
16
|
+
.replace(/\s+/g, ' ')
|
|
17
|
+
.trim();
|
|
18
|
+
}
|
|
19
|
+
const rule = {
|
|
20
|
+
meta: {
|
|
21
|
+
type: 'suggestion',
|
|
22
|
+
docs: {
|
|
23
|
+
description: 'Require meaningful, descriptive test names',
|
|
24
|
+
category: 'Best Practices',
|
|
25
|
+
recommended: true,
|
|
26
|
+
url: 'https://github.com/acahet-automation-org/playwright-standards/blob/main/docs/rules/require-test-description.md',
|
|
27
|
+
},
|
|
28
|
+
messages: {
|
|
29
|
+
missingDescription: 'test() must have a description as the first argument.',
|
|
30
|
+
missingTestId: 'Test description "{{name}}" must end with a test ID in the format nrt-123.',
|
|
31
|
+
tooShort: 'Test description "{{name}}" is too short (min {{min}} characters). Describe observable behaviour.',
|
|
32
|
+
vagueDescription: 'Test description "{{name}}" is too vague. Describe what the user sees or does.',
|
|
33
|
+
},
|
|
34
|
+
schema: [
|
|
35
|
+
{
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
minLength: { type: 'number', minimum: 1 },
|
|
39
|
+
},
|
|
40
|
+
additionalProperties: false,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
create(context) {
|
|
45
|
+
const options = context.options[0] ?? {};
|
|
46
|
+
const minLength = options.minLength ?? MIN_DESCRIPTION_LENGTH;
|
|
47
|
+
return {
|
|
48
|
+
CallExpression(node) {
|
|
49
|
+
if (node.callee.type !== 'Identifier')
|
|
50
|
+
return;
|
|
51
|
+
const name = node.callee.name;
|
|
52
|
+
if (!TEST_FUNCTIONS.has(name))
|
|
53
|
+
return;
|
|
54
|
+
const firstArg = node.arguments[0];
|
|
55
|
+
if (!firstArg) {
|
|
56
|
+
context.report({ node, messageId: 'missingDescription' });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (firstArg.type === 'TemplateLiteral') {
|
|
60
|
+
const cooked = firstArg.quasis
|
|
61
|
+
.map((q) => q.value.cooked ?? '')
|
|
62
|
+
.join('');
|
|
63
|
+
const description = cooked.trim();
|
|
64
|
+
const meaningfulDescription = getMeaningfulDescription(description);
|
|
65
|
+
if (!TEST_ID_AT_END_PATTERN.test(description)) {
|
|
66
|
+
context.report({
|
|
67
|
+
node: firstArg,
|
|
68
|
+
messageId: 'missingTestId',
|
|
69
|
+
data: { name: description },
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (VAGUE_PATTERNS.some((pattern) => pattern.test(meaningfulDescription))) {
|
|
74
|
+
context.report({
|
|
75
|
+
node: firstArg,
|
|
76
|
+
messageId: 'vagueDescription',
|
|
77
|
+
data: { name: meaningfulDescription },
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (meaningfulDescription.length < minLength) {
|
|
82
|
+
context.report({
|
|
83
|
+
node: firstArg,
|
|
84
|
+
messageId: 'tooShort',
|
|
85
|
+
data: {
|
|
86
|
+
name: meaningfulDescription,
|
|
87
|
+
min: String(minLength),
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (firstArg.type !== 'Literal')
|
|
94
|
+
return;
|
|
95
|
+
const description = String(firstArg.value).trim();
|
|
96
|
+
const meaningfulDescription = getMeaningfulDescription(description);
|
|
97
|
+
if (!TEST_ID_AT_END_PATTERN.test(description)) {
|
|
98
|
+
context.report({
|
|
99
|
+
node: firstArg,
|
|
100
|
+
messageId: 'missingTestId',
|
|
101
|
+
data: { name: description },
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (VAGUE_PATTERNS.some((pattern) => pattern.test(meaningfulDescription))) {
|
|
106
|
+
context.report({
|
|
107
|
+
node: firstArg,
|
|
108
|
+
messageId: 'vagueDescription',
|
|
109
|
+
data: { name: meaningfulDescription },
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (meaningfulDescription.length < minLength) {
|
|
114
|
+
context.report({
|
|
115
|
+
node: firstArg,
|
|
116
|
+
messageId: 'tooShort',
|
|
117
|
+
data: {
|
|
118
|
+
name: meaningfulDescription,
|
|
119
|
+
min: String(minLength),
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
exports.default = rule;
|
|
129
|
+
//# sourceMappingURL=require-test-description.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-test-description.js","sourceRoot":"","sources":["../../../src/eslint/rules/require-test-description.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Rule } from 'eslint';
|
|
2
|
+
export interface RuleModule extends Rule.RuleModule {
|
|
3
|
+
meta: Rule.RuleMetaData & {
|
|
4
|
+
docs: {
|
|
5
|
+
description: string;
|
|
6
|
+
category: string;
|
|
7
|
+
recommended: boolean;
|
|
8
|
+
url?: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export type RuleMap = Record<string, RuleModule>;
|
|
13
|
+
export type Severity = 'error' | 'warn' | 'off';
|
|
14
|
+
export interface ConfigRules {
|
|
15
|
+
[ruleName: string]: Severity | [Severity, ...unknown[]];
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/eslint/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,MAAM,WAAW,UAAW,SAAQ,IAAI,CAAC,UAAU;IAClD,IAAI,EAAE,IAAI,CAAC,YAAY,GAAG;QACzB,IAAI,EAAE;YACL,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,WAAW,EAAE,OAAO,CAAC;YACrB,GAAG,CAAC,EAAE,MAAM,CAAC;SACb,CAAC;KACF,CAAC;CACF;AAED,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAEjD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEhD,MAAM,WAAW,WAAW;IAC3B,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,CAAC,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;CACxD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/eslint/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Rule } from 'eslint';
|
|
2
|
+
import { Node, CallExpression } from 'estree';
|
|
3
|
+
export declare function isPlaywrightFile(filename: string): boolean;
|
|
4
|
+
export declare function isWaitForTimeout(node: CallExpression): boolean;
|
|
5
|
+
export declare function getMethodName(node: CallExpression): string | null;
|
|
6
|
+
export declare function getObjectName(node: CallExpression): string | null;
|
|
7
|
+
export declare function findAncestor(node: Node, context: Rule.RuleContext, predicate: (n: Node) => boolean): Node | null;
|
|
8
|
+
export declare const BRITTLE_SELECTOR_PATTERNS: RegExp[];
|
|
9
|
+
export declare function isBrittleSelector(selector: string): boolean;
|
|
10
|
+
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../src/eslint/utils/ast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,cAAc,EAAgC,MAAM,QAAQ,CAAC;AAE5E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAK1D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAO9D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAIjE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAIjE;AAED,wBAAgB,YAAY,CAC3B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,IAAI,CAAC,WAAW,EACzB,SAAS,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,GAC7B,IAAI,GAAG,IAAI,CAMb;AAED,eAAO,MAAM,yBAAyB,EAAE,MAAM,EAS7C,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI3D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BRITTLE_SELECTOR_PATTERNS = void 0;
|
|
4
|
+
exports.isPlaywrightFile = isPlaywrightFile;
|
|
5
|
+
exports.isWaitForTimeout = isWaitForTimeout;
|
|
6
|
+
exports.getMethodName = getMethodName;
|
|
7
|
+
exports.getObjectName = getObjectName;
|
|
8
|
+
exports.findAncestor = findAncestor;
|
|
9
|
+
exports.isBrittleSelector = isBrittleSelector;
|
|
10
|
+
function isPlaywrightFile(filename) {
|
|
11
|
+
return (/\.(spec|test)\.[jt]sx?$/.test(filename) ||
|
|
12
|
+
/[/\\](e2e|tests?)[/\\]/.test(filename));
|
|
13
|
+
}
|
|
14
|
+
function isWaitForTimeout(node) {
|
|
15
|
+
if (node.callee.type !== 'MemberExpression')
|
|
16
|
+
return false;
|
|
17
|
+
const callee = node.callee;
|
|
18
|
+
return (callee.property.type === 'Identifier' &&
|
|
19
|
+
callee.property.name === 'waitForTimeout');
|
|
20
|
+
}
|
|
21
|
+
function getMethodName(node) {
|
|
22
|
+
if (node.callee.type !== 'MemberExpression')
|
|
23
|
+
return null;
|
|
24
|
+
const prop = node.callee.property;
|
|
25
|
+
return prop.type === 'Identifier' ? prop.name : null;
|
|
26
|
+
}
|
|
27
|
+
function getObjectName(node) {
|
|
28
|
+
if (node.callee.type !== 'MemberExpression')
|
|
29
|
+
return null;
|
|
30
|
+
const obj = node.callee.object;
|
|
31
|
+
return obj.type === 'Identifier' ? obj.name : null;
|
|
32
|
+
}
|
|
33
|
+
function findAncestor(node, context, predicate) {
|
|
34
|
+
const ancestors = context.getAncestors();
|
|
35
|
+
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
36
|
+
if (predicate(ancestors[i]))
|
|
37
|
+
return ancestors[i];
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
exports.BRITTLE_SELECTOR_PATTERNS = [
|
|
42
|
+
/^\.[\w-]+/,
|
|
43
|
+
/^#[\w-]+/,
|
|
44
|
+
/nth-child/,
|
|
45
|
+
/nth-of-type/,
|
|
46
|
+
/^\/\//,
|
|
47
|
+
/\s*>\s*/,
|
|
48
|
+
/\s*\+\s*/,
|
|
49
|
+
/\s*~\s*/,
|
|
50
|
+
];
|
|
51
|
+
function isBrittleSelector(selector) {
|
|
52
|
+
return exports.BRITTLE_SELECTOR_PATTERNS.some((pattern) => pattern.test(selector.trim()));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=ast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../../../src/eslint/utils/ast.ts"],"names":[],"mappings":";;;AAGA,4CAKC;AAED,4CAOC;AAED,sCAIC;AAED,sCAIC;AAED,oCAUC;AAaD,8CAIC;AAvDD,SAAgB,gBAAgB,CAAC,QAAgB;IAChD,OAAO,CACN,yBAAyB,CAAC,IAAI,CAAC,QAAQ,CAAC;QACxC,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CACvC,CAAC;AACH,CAAC;AAED,SAAgB,gBAAgB,CAAC,IAAoB;IACpD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,MAA0B,CAAC;IAC/C,OAAO,CACN,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;QACpC,MAAM,CAAC,QAAuB,CAAC,IAAI,KAAK,gBAAgB,CACzD,CAAC;AACH,CAAC;AAED,SAAgB,aAAa,CAAC,IAAoB;IACjD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,IAAI,GAAI,IAAI,CAAC,MAA2B,CAAC,QAAQ,CAAC;IACxD,OAAO,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAE,IAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC;AAED,SAAgB,aAAa,CAAC,IAAoB;IACjD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO,IAAI,CAAC;IACzD,MAAM,GAAG,GAAI,IAAI,CAAC,MAA2B,CAAC,MAAM,CAAC;IACrD,OAAO,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAE,GAAkB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC;AAED,SAAgB,YAAY,CAC3B,IAAU,EACV,OAAyB,EACzB,SAA+B;IAE/B,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAEY,QAAA,yBAAyB,GAAa;IAClD,WAAW;IACX,UAAU;IACV,WAAW;IACX,aAAa;IACb,OAAO;IACP,SAAS;IACT,UAAU;IACV,SAAS;CACT,CAAC;AAEF,SAAgB,iBAAiB,CAAC,QAAgB;IACjD,OAAO,iCAAyB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CACjD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAC7B,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @acahet/pw-standard
|
|
3
|
+
*
|
|
4
|
+
* Root barrel. Prefer importing from the specific entry point
|
|
5
|
+
* to keep bundle size small:
|
|
6
|
+
*
|
|
7
|
+
* import plugin from '@acahet/pw-standard/eslint'
|
|
8
|
+
* import { baseConfig } from '@acahet/pw-standard/playwright'
|
|
9
|
+
* import { BasePage } from '@acahet/pw-standard/base'
|
|
10
|
+
*
|
|
11
|
+
* This barrel is available for tooling that needs everything at once.
|
|
12
|
+
*/
|
|
13
|
+
export { default as eslintPlugin } from './eslint/index';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
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.eslintPlugin = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* @acahet/pw-standard
|
|
9
|
+
*
|
|
10
|
+
* Root barrel. Prefer importing from the specific entry point
|
|
11
|
+
* to keep bundle size small:
|
|
12
|
+
*
|
|
13
|
+
* import plugin from '@acahet/pw-standard/eslint'
|
|
14
|
+
* import { baseConfig } from '@acahet/pw-standard/playwright'
|
|
15
|
+
* import { BasePage } from '@acahet/pw-standard/base'
|
|
16
|
+
*
|
|
17
|
+
* This barrel is available for tooling that needs everything at once.
|
|
18
|
+
*/
|
|
19
|
+
var index_1 = require("./eslint/index");
|
|
20
|
+
Object.defineProperty(exports, "eslintPlugin", { enumerable: true, get: function () { return __importDefault(index_1).default; } });
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;GAWG;AACH,wCAAyD;AAAhD,sHAAA,OAAO,OAAgB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* Backwards-compatible bridge export.
|
|
19
|
+
*
|
|
20
|
+
* New consumers should import from `@acahet/playwright-configs` directly.
|
|
21
|
+
*/
|
|
22
|
+
__exportStar(require("@acahet/playwright-configs"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/playwright/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;GAIG;AACH,6DAA2C"}
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@acahet/playwright-rules",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Shared Playwright + TypeScript standards: ESLint rules, configs, base classes and fixtures",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
},
|
|
13
|
+
"./eslint": {
|
|
14
|
+
"import": "./dist/eslint/index.js",
|
|
15
|
+
"require": "./dist/eslint/index.js",
|
|
16
|
+
"types": "./dist/eslint/index.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./playwright": {
|
|
19
|
+
"import": "./dist/playwright/index.js",
|
|
20
|
+
"require": "./dist/playwright/index.js",
|
|
21
|
+
"types": "./dist/playwright/index.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./tsconfig/base": "./src/tsconfig/base.json",
|
|
24
|
+
"./tsconfig/strict": "./src/tsconfig/strict.json",
|
|
25
|
+
"./base": {
|
|
26
|
+
"import": "./dist/base/index.js",
|
|
27
|
+
"require": "./dist/base/index.js",
|
|
28
|
+
"types": "./dist/base/index.d.ts"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"src/tsconfig",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc --project tsconfig.json",
|
|
38
|
+
"build:watch": "tsc --project tsconfig.json --watch",
|
|
39
|
+
"test": "jest --config jest.config.js",
|
|
40
|
+
"test:watch": "jest --config jest.config.js --watch",
|
|
41
|
+
"test:coverage": "jest --config jest.config.js --coverage",
|
|
42
|
+
"lint": "eslint src --ext .ts",
|
|
43
|
+
"prepublishOnly": "npm run build && npm test"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"eslint",
|
|
47
|
+
"eslint-plugin",
|
|
48
|
+
"playwright",
|
|
49
|
+
"typescript",
|
|
50
|
+
"testing",
|
|
51
|
+
"e2e",
|
|
52
|
+
"standards"
|
|
53
|
+
],
|
|
54
|
+
"author": "",
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/acahet-automation-org/playwright-toolbox.git",
|
|
59
|
+
"directory": "packages/playwright-rules"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"eslint": ">=8.0.0",
|
|
63
|
+
"@playwright/test": ">=1.40.0",
|
|
64
|
+
"@acahet/playwright-config": ">=1.2.0"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"@playwright/test": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@playwright/test": "^1.42.0",
|
|
73
|
+
"@types/eslint": "^8.56.0",
|
|
74
|
+
"@types/jest": "^29.5.12",
|
|
75
|
+
"@types/node": "^20.11.0",
|
|
76
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
77
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
78
|
+
"eslint": "^8.56.0",
|
|
79
|
+
"jest": "^29.7.0",
|
|
80
|
+
"ts-jest": "^29.1.2",
|
|
81
|
+
"typescript": "^5.3.3"
|
|
82
|
+
},
|
|
83
|
+
"engines": {
|
|
84
|
+
"node": ">=18.0.0"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "@acahet/pw-standard — base",
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"target": "ES2020",
|
|
6
|
+
"module": "commonjs",
|
|
7
|
+
"lib": ["ES2020", "DOM"],
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"noUnusedLocals": true,
|
|
17
|
+
"noUnusedParameters": true,
|
|
18
|
+
"noImplicitReturns": true,
|
|
19
|
+
"noFallthroughCasesInSwitch": true
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/tsconfig",
|
|
3
|
+
"display": "@acahet/pw-standard — strict",
|
|
4
|
+
"extends": "./base.json",
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"strict": true,
|
|
7
|
+
"exactOptionalPropertyTypes": true,
|
|
8
|
+
"noPropertyAccessFromIndexSignature": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true
|
|
10
|
+
}
|
|
11
|
+
}
|