@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.
Files changed (52) hide show
  1. package/README.md +50 -0
  2. package/dist/base/index.d.ts +15 -0
  3. package/dist/base/index.d.ts.map +1 -0
  4. package/dist/base/index.js +16 -0
  5. package/dist/base/index.js.map +1 -0
  6. package/dist/eslint/index.d.ts +87 -0
  7. package/dist/eslint/index.d.ts.map +1 -0
  8. package/dist/eslint/index.js +82 -0
  9. package/dist/eslint/index.js.map +1 -0
  10. package/dist/eslint/rules/no-brittle-selectors.d.ts +4 -0
  11. package/dist/eslint/rules/no-brittle-selectors.d.ts.map +1 -0
  12. package/dist/eslint/rules/no-brittle-selectors.js +47 -0
  13. package/dist/eslint/rules/no-brittle-selectors.js.map +1 -0
  14. package/dist/eslint/rules/no-focused-tests.d.ts +4 -0
  15. package/dist/eslint/rules/no-focused-tests.d.ts.map +1 -0
  16. package/dist/eslint/rules/no-focused-tests.js +58 -0
  17. package/dist/eslint/rules/no-focused-tests.js.map +1 -0
  18. package/dist/eslint/rules/no-page-pause.d.ts +4 -0
  19. package/dist/eslint/rules/no-page-pause.d.ts.map +1 -0
  20. package/dist/eslint/rules/no-page-pause.js +32 -0
  21. package/dist/eslint/rules/no-page-pause.js.map +1 -0
  22. package/dist/eslint/rules/no-wait-for-timeout.d.ts +4 -0
  23. package/dist/eslint/rules/no-wait-for-timeout.d.ts.map +1 -0
  24. package/dist/eslint/rules/no-wait-for-timeout.js +29 -0
  25. package/dist/eslint/rules/no-wait-for-timeout.js.map +1 -0
  26. package/dist/eslint/rules/prefer-web-first-assertions.d.ts +4 -0
  27. package/dist/eslint/rules/prefer-web-first-assertions.d.ts.map +1 -0
  28. package/dist/eslint/rules/prefer-web-first-assertions.js +78 -0
  29. package/dist/eslint/rules/prefer-web-first-assertions.js.map +1 -0
  30. package/dist/eslint/rules/require-test-description.d.ts +4 -0
  31. package/dist/eslint/rules/require-test-description.d.ts.map +1 -0
  32. package/dist/eslint/rules/require-test-description.js +129 -0
  33. package/dist/eslint/rules/require-test-description.js.map +1 -0
  34. package/dist/eslint/types.d.ts +17 -0
  35. package/dist/eslint/types.d.ts.map +1 -0
  36. package/dist/eslint/types.js +3 -0
  37. package/dist/eslint/types.js.map +1 -0
  38. package/dist/eslint/utils/ast.d.ts +10 -0
  39. package/dist/eslint/utils/ast.d.ts.map +1 -0
  40. package/dist/eslint/utils/ast.js +54 -0
  41. package/dist/eslint/utils/ast.js.map +1 -0
  42. package/dist/index.d.ts +14 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +21 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/playwright/index.d.ts +7 -0
  47. package/dist/playwright/index.d.ts.map +1 -0
  48. package/dist/playwright/index.js +23 -0
  49. package/dist/playwright/index.js.map +1 -0
  50. package/package.json +86 -0
  51. package/src/tsconfig/base.json +21 -0
  52. 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,4 @@
1
+ import { RuleModule } from '../types';
2
+ declare const rule: RuleModule;
3
+ export default rule;
4
+ //# sourceMappingURL=no-brittle-selectors.d.ts.map
@@ -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,4 @@
1
+ import { RuleModule } from '../types';
2
+ declare const rule: RuleModule;
3
+ export default rule;
4
+ //# sourceMappingURL=no-focused-tests.d.ts.map
@@ -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,4 @@
1
+ import { RuleModule } from '../types';
2
+ declare const rule: RuleModule;
3
+ export default rule;
4
+ //# sourceMappingURL=no-page-pause.d.ts.map
@@ -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,4 @@
1
+ import { RuleModule } from '../types';
2
+ declare const rule: RuleModule;
3
+ export default rule;
4
+ //# sourceMappingURL=no-wait-for-timeout.d.ts.map
@@ -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,4 @@
1
+ import { RuleModule } from '../types';
2
+ declare const rule: RuleModule;
3
+ export default rule;
4
+ //# sourceMappingURL=prefer-web-first-assertions.d.ts.map
@@ -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,4 @@
1
+ import { RuleModule } from '../types';
2
+ declare const rule: RuleModule;
3
+ export default rule;
4
+ //# sourceMappingURL=require-test-description.d.ts.map
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -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"}
@@ -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,7 @@
1
+ /**
2
+ * Backwards-compatible bridge export.
3
+ *
4
+ * New consumers should import from `@acahet/playwright-configs` directly.
5
+ */
6
+ export * from '@acahet/playwright-configs';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -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
+ }