pw-core 1.2.1 → 1.3.1

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 (61) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +145 -421
  3. package/dist/codegen/action-formatter.d.ts +19 -0
  4. package/dist/codegen/action-formatter.js +160 -0
  5. package/dist/codegen/action-processor.d.ts +23 -0
  6. package/dist/codegen/action-processor.js +112 -0
  7. package/dist/codegen/floating-panel/client.d.ts +14 -1
  8. package/dist/codegen/floating-panel/client.js +20 -25
  9. package/dist/codegen/floating-panel/manager.js +16 -22
  10. package/dist/codegen/generator/action.validator.d.ts +2 -1
  11. package/dist/codegen/generator/action.validator.js +2 -1
  12. package/dist/codegen/generator/candidate-scorer.d.ts +7 -0
  13. package/dist/codegen/generator/candidate-scorer.js +206 -0
  14. package/dist/codegen/generator/dom-scanner.d.ts +39 -0
  15. package/dist/codegen/generator/dom-scanner.js +429 -0
  16. package/dist/codegen/generator/id-stability.d.ts +6 -0
  17. package/dist/codegen/generator/id-stability.js +38 -0
  18. package/dist/codegen/generator/index.d.ts +8 -10
  19. package/dist/codegen/generator/index.js +23 -678
  20. package/dist/codegen/generator/key-builder.d.ts +13 -0
  21. package/dist/codegen/generator/key-builder.js +32 -0
  22. package/dist/codegen/hover-tracker/client.d.ts +5 -0
  23. package/dist/codegen/hover-tracker/client.js +14 -15
  24. package/dist/codegen/hover-tracker/manager.js +2 -6
  25. package/dist/codegen/index.d.ts +9 -32
  26. package/dist/codegen/index.js +9 -1128
  27. package/dist/codegen/key-utils.d.ts +16 -0
  28. package/dist/codegen/key-utils.js +29 -1
  29. package/dist/codegen/project-finder.d.ts +29 -0
  30. package/dist/codegen/project-finder.js +283 -0
  31. package/dist/codegen/registry-matcher.d.ts +27 -0
  32. package/dist/codegen/registry-matcher.js +254 -0
  33. package/dist/codegen/registry-store.d.ts +52 -0
  34. package/dist/codegen/registry-store.js +652 -0
  35. package/dist/codegen/selector-parser.d.ts +16 -0
  36. package/dist/codegen/selector-parser.js +121 -0
  37. package/dist/codegen/types.d.ts +18 -1
  38. package/dist/codegen/uniqueness.d.ts +3 -0
  39. package/dist/codegen/uniqueness.js +15 -0
  40. package/dist/component/table.d.ts +2 -2
  41. package/dist/component/table.js +7 -6
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.js +19 -0
  44. package/dist/page/actions/locator-actions.d.ts +6 -10
  45. package/dist/page/actions/locator-actions.js +24 -23
  46. package/dist/page/assertions/verify-chain.d.ts +11 -13
  47. package/dist/page/assertions/verify-chain.js +26 -7
  48. package/dist/page/assertions/verify-helpers.d.ts +5 -15
  49. package/dist/page/config.d.ts +25 -25
  50. package/dist/page/locators/dynamic-locator-resolver.js +22 -9
  51. package/dist/page/locators/resolver.d.ts +17 -11
  52. package/dist/page/locators/resolver.js +84 -78
  53. package/dist/page/registry.d.ts +35 -35
  54. package/dist/page/registry.js +86 -82
  55. package/dist/page/typed-page.d.ts +1 -0
  56. package/dist/page/typed-page.js +22 -12
  57. package/dist/page/types/proxy-methods.d.ts +11 -19
  58. package/dist/page/types/validation.d.ts +1 -1
  59. package/dist/page/utils/formatter.d.ts +3 -3
  60. package/dist/page/utils/formatter.js +5 -2
  61. package/package.json +6 -3
@@ -7,9 +7,36 @@ exports.createPageRegistry = createPageRegistry;
7
7
  const test_1 = __importDefault(require("@playwright/test"));
8
8
  const typed_page_1 = require("./typed-page");
9
9
  const resolver_1 = require("./locators/resolver");
10
- function createPageRegistryWithClasses(registry, classes, base) {
10
+ // Local runtime key transformation helpers for fixture aliases.
11
+ // Intentionally kept local to preserve runtime isolation (page/ does not depend on codegen/).
12
+ function toUnprefixedPageKey(key) {
13
+ return key.slice(6).charAt(0).toLowerCase() + key.slice(7);
14
+ }
15
+ function toWorkerPageKey(key) {
16
+ return key.startsWith('worker') ? key : `worker${key.charAt(0).toUpperCase()}${key.slice(1)}`;
17
+ }
18
+ function getPageKeyAliases(key) {
19
+ if (key.startsWith('worker')) {
20
+ const unprefixed = toUnprefixedPageKey(key);
21
+ return { pageKey: unprefixed || key, workerKey: key };
22
+ }
23
+ return { pageKey: key, workerKey: toWorkerPageKey(key) };
24
+ }
25
+ function createPageFixture(PageClass) {
26
+ return async ({ page }, use) => {
27
+ await use(new PageClass(page));
28
+ };
29
+ }
30
+ function createWorkerFixture(PageClass) {
31
+ return [
32
+ async ({ workerPage }, use) => {
33
+ await use(new PageClass(workerPage));
34
+ },
35
+ { scope: 'worker' }
36
+ ];
37
+ }
38
+ function createRegistryFixtures(registry, classes) {
11
39
  const fixtures = {
12
- // Shared worker context and page
13
40
  workerContext: [
14
41
  async ({ browser }, use) => {
15
42
  const context = await browser.newContext();
@@ -20,82 +47,59 @@ function createPageRegistryWithClasses(registry, classes, base) {
20
47
  ],
21
48
  workerPage: [
22
49
  async ({ workerContext }, use) => {
23
- const page = await workerContext.newPage();
24
- await use(page);
50
+ await use(await workerContext.newPage());
25
51
  },
26
52
  { scope: 'worker' }
27
53
  ]
28
54
  };
29
55
  for (const key of Object.keys(registry)) {
30
- // Page fixture for key
31
- fixtures[key] = async ({ page }, use) => {
32
- const PageClass = classes[key];
33
- const instance = new PageClass(page);
34
- await use(instance);
35
- };
36
- // Page fixture for un-prefixed key (if key starts with worker)
37
- if (key.startsWith('worker')) {
38
- const unPrefixed = key.slice(6).charAt(0).toLowerCase() + key.slice(7);
39
- if (unPrefixed && !fixtures[unPrefixed]) {
40
- fixtures[unPrefixed] = async ({ page }, use) => {
41
- const PageClass = classes[key];
42
- const instance = new PageClass(page);
43
- await use(instance);
44
- };
45
- }
46
- }
47
- // Worker fixture for worker-prefixed key
48
- const workerKey = key.startsWith('worker') ? key : `worker${key.charAt(0).toUpperCase()}${key.slice(1)}`;
49
- fixtures[workerKey] = [
50
- async ({ workerPage }, use) => {
51
- const PageClass = classes[key];
52
- const instance = new PageClass(workerPage);
53
- await use(instance);
54
- },
55
- { scope: 'worker' }
56
- ];
56
+ const PageClass = classes[key];
57
+ const { pageKey, workerKey } = getPageKeyAliases(key);
58
+ fixtures[pageKey] = createPageFixture(PageClass);
59
+ fixtures[workerKey] = createWorkerFixture(PageClass);
57
60
  }
61
+ return fixtures;
62
+ }
63
+ function createPageRegistryWithClasses(registry, classes, base) {
64
+ const fixtures = createRegistryFixtures(registry, classes);
58
65
  // Copy worker and non-worker aliases in pages and classes dictionaries
59
66
  const extendedClasses = { ...classes };
60
67
  for (const key of Object.keys(classes)) {
61
- if (key.startsWith('worker')) {
62
- const unPrefixed = key.slice(6).charAt(0).toLowerCase() + key.slice(7);
63
- if (unPrefixed && !extendedClasses[unPrefixed]) {
64
- extendedClasses[unPrefixed] = classes[key];
65
- }
68
+ const { pageKey, workerKey } = getPageKeyAliases(key);
69
+ if (!extendedClasses[pageKey]) {
70
+ extendedClasses[pageKey] = classes[key];
66
71
  }
67
- else {
68
- const workerKey = `worker${key.charAt(0).toUpperCase()}${key.slice(1)}`;
69
- if (!extendedClasses[workerKey]) {
70
- extendedClasses[workerKey] = classes[key];
71
- }
72
+ if (!extendedClasses[workerKey]) {
73
+ extendedClasses[workerKey] = classes[key];
72
74
  }
73
75
  }
74
- const testRunner = base.extend(fixtures);
75
- testRunner.pages = extendedClasses;
76
- testRunner.classes = extendedClasses;
77
- const originalExtend = testRunner.extend.bind(testRunner);
78
- testRunner.extend = (overrides, customBase = test_1.default) => {
76
+ // Playwright compatibility boundary: extend test runner with fixtures and attach registry dictionaries
77
+ const rawRunner = base.extend(fixtures);
78
+ rawRunner.pages = extendedClasses;
79
+ rawRunner.classes = extendedClasses;
80
+ const originalExtend = rawRunner.extend.bind(rawRunner);
81
+ rawRunner.extend = (overrides, customBase = test_1.default) => {
79
82
  if (!overrides) {
80
83
  return originalExtend();
81
84
  }
82
- const isPlaywrightFixtures = Object.values(overrides).every((val) => (typeof val === 'function' && !val.toString().startsWith('class')) || Array.isArray(val));
85
+ const overridesObj = overrides;
86
+ const isPlaywrightFixtures = Object.values(overridesObj).every((val) => (typeof val === 'function' && !val.toString().startsWith('class')) || Array.isArray(val));
83
87
  if (isPlaywrightFixtures) {
84
88
  const runner = originalExtend(overrides);
85
89
  runner.pages = extendedClasses;
86
90
  runner.classes = extendedClasses;
87
- runner.extend = testRunner.extend;
91
+ runner.extend = rawRunner.extend;
88
92
  return runner;
89
93
  }
90
94
  const newClasses = { ...classes };
91
- for (const key of Object.keys(overrides)) {
92
- if (overrides[key]) {
93
- newClasses[key] = overrides[key];
95
+ for (const key of Object.keys(overridesObj)) {
96
+ if (overridesObj[key]) {
97
+ newClasses[key] = overridesObj[key];
94
98
  }
95
99
  }
96
- return createPageRegistryWithClasses(registry, newClasses, customBase);
100
+ return createPageRegistryWithClasses(registry, newClasses, (customBase ?? test_1.default));
97
101
  };
98
- return testRunner;
102
+ return rawRunner;
99
103
  }
100
104
  /**
101
105
  * Creates a page registry that registers page objects as Playwright fixtures,
@@ -108,35 +112,35 @@ function createPageRegistryWithClasses(registry, classes, base) {
108
112
  *
109
113
  * // returns the extended test runner directly
110
114
  * const test = createPageRegistry({
111
- codegenPage: {
112
- url: '/',
113
- selectors: {
114
- '{item}': {
115
- item: ['why-pw-core', 'why-not-playwright', 'registry', 'typed-page', 'features'],
116
- selector: '[data-parent-id="{item}"]'
117
- },
118
- copyToClipboardBtn: '.page',
119
- dynamicLocators: 'text="Dynamic Locators" >> nth=0',
120
- rootrailthumbright: '#rootRailThumbRight',
121
- 'text{item}': {
122
- item: ['Auto Steps', 'Capabilities >> nth=0', 'Secret Masking'],
123
- selector: 'text="{item}"'
124
- },
125
- tshirts: '.title-title',
126
- tShirts: 'internal:role=link[name="T-Shirts"s]'
127
- },
128
- testIds: {
129
- qaWorkspaceBtn: 'active-workspace-btn',
130
- wsOptionApp: 'ws-option-app'
131
- }
132
- },
133
- blankPage: {
134
- url: '/',
135
- selectors: {
136
- element: '[data-pw-cursor="pointer"]'
137
- }
138
- }
139
- });
115
+ codegenPage: {
116
+ url: '/',
117
+ selectors: {
118
+ '{item}': {
119
+ item: ['why-pw-core', 'why-not-playwright', 'registry', 'typed-page', 'features'],
120
+ selector: '[data-parent-id="{item}"]'
121
+ },
122
+ copyToClipboardBtn: '.page',
123
+ dynamicLocators: 'text="Dynamic Locators" >> nth=0',
124
+ rootrailthumbright: '#rootRailThumbRight',
125
+ 'text{item}': {
126
+ item: ['Auto Steps', 'Capabilities >> nth=0', 'Secret Masking'],
127
+ selector: 'text="{item}"'
128
+ },
129
+ tshirts: '.title-title',
130
+ tShirts: 'internal:role=link[name="T-Shirts"s]'
131
+ },
132
+ testIds: {
133
+ qaWorkspaceBtn: 'active-workspace-btn',
134
+ wsOptionApp: 'ws-option-app'
135
+ }
136
+ },
137
+ blankPage: {
138
+ url: '/',
139
+ selectors: {
140
+ element: '[data-pw-cursor="pointer"]'
141
+ }
142
+ }
143
+ });
140
144
  *
141
145
  * // returns page classes only when accessing .pages
142
146
  * const pages = createPageRegistry({
@@ -10,6 +10,7 @@ declare class TypedPageClass<T extends PageConfig> {
10
10
  constructor(context: Page | Locator, config: T, options?: {
11
11
  timeout?: number;
12
12
  });
13
+ private resolveTarget;
13
14
  /** Navigate to the URL from page config. */
14
15
  goto(options?: {
15
16
  referrer?: string;
@@ -17,12 +17,13 @@ class TypedPageClass {
17
17
  timeout;
18
18
  constructor(context, config, options) {
19
19
  this.context = context;
20
- this.page = typeof context.page === 'function' ? context.page() : context;
20
+ const hasPageFn = typeof context.page === 'function';
21
+ this.page = hasPageFn ? context.page() : context;
21
22
  this.config = config;
22
23
  this.url = config.url;
23
24
  this.timeout = options?.timeout;
24
25
  (0, resolver_1.defineLocators)(this, this.context, this.config);
25
- (0, locator_actions_1.defineActionMethods)(this, this.resolveLocator.bind(this), this.timeout);
26
+ (0, locator_actions_1.defineActionMethods)(this, this.resolveTarget.bind(this), this.timeout);
26
27
  // Auto-wrap subclass methods with Playwright test.step
27
28
  const builtInMethods = new Set([
28
29
  'constructor',
@@ -79,6 +80,9 @@ class TypedPageClass {
79
80
  proto = Object.getPrototypeOf(proto);
80
81
  }
81
82
  }
83
+ resolveTarget(target, options) {
84
+ return (0, resolver_1.resolveLocator)(this.context, this.config, target, options);
85
+ }
82
86
  /** Navigate to the URL from page config. */
83
87
  async goto(options) {
84
88
  return (0, page_actions_1.goto)(this.page, this.url, this.constructor.name, options, (0, caller_location_1.getCallerLocation)());
@@ -104,7 +108,7 @@ class TypedPageClass {
104
108
  return (0, page_actions_1.waitForURL)(this.page, this.url, this.constructor.name, urlOrOptions, options, (0, caller_location_1.getCallerLocation)());
105
109
  }
106
110
  resolveLocator(target, options) {
107
- return (0, resolver_1.resolveLocator)(this.context, this.config, target, options);
111
+ return this.resolveTarget(target, options);
108
112
  }
109
113
  /** Resolve a config key to a proxied Locator with step-wrapped methods. */
110
114
  locator(target, options) {
@@ -126,26 +130,32 @@ class TypedPageClass {
126
130
  options = arg;
127
131
  }
128
132
  }
129
- let loc = (0, resolver_1.resolveLocator)(this.context, this.config, keys[0], options);
130
- for (let i = 1; i < keys.length; i++) {
131
- loc = (0, resolver_1.resolveLocator)(loc, this.config, keys[i], options);
133
+ const [firstKey, ...remainingKeys] = keys;
134
+ if (!firstKey) {
135
+ throw new Error('chain requires at least one locator key.');
136
+ }
137
+ let loc = (0, resolver_1.resolveLocator)(this.context, this.config, firstKey, { raw: true });
138
+ for (let i = 0; i < remainingKeys.length; i++) {
139
+ const key = remainingKeys[i];
140
+ const isLast = i === remainingKeys.length - 1;
141
+ loc = (0, resolver_1.resolveLocator)(loc, this.config, key, isLast ? options : { raw: true });
132
142
  }
133
- return loc;
143
+ return remainingKeys.length > 0 ? loc : (0, resolver_1.resolveLocator)(this.context, this.config, firstKey, options);
134
144
  }
135
145
  /** Chainable assertions on config keys. Supports `.soft` for soft assertions. */
136
146
  get verify() {
137
- const fn = (target, opts) => (0, verify_chain_1.createVerifyChain)(this.resolveLocator.bind(this), target, opts, false);
138
- fn.soft = (target, opts) => (0, verify_chain_1.createVerifyChain)(this.resolveLocator.bind(this), target, opts, true);
147
+ const fn = ((target, opts) => (0, verify_chain_1.createVerifyChain)(this.resolveTarget.bind(this), target, opts, false));
148
+ fn.soft = (target, opts) => (0, verify_chain_1.createVerifyChain)(this.resolveTarget.bind(this), target, opts, true);
139
149
  return fn;
140
150
  }
141
151
  async verifyHidden(target, options) {
142
- return (0, verify_helpers_1.verifyHidden)(this.resolveLocator.bind(this), target, options, (0, caller_location_1.getCallerLocation)());
152
+ return (0, verify_helpers_1.verifyHidden)(this.resolveTarget.bind(this), target, options, (0, caller_location_1.getCallerLocation)());
143
153
  }
144
154
  async verifyEnabled(target, options) {
145
- return (0, verify_helpers_1.verifyEnabled)(this.resolveLocator.bind(this), target, options, (0, caller_location_1.getCallerLocation)());
155
+ return (0, verify_helpers_1.verifyEnabled)(this.resolveTarget.bind(this), target, options, (0, caller_location_1.getCallerLocation)());
146
156
  }
147
157
  async verifyDisabled(target, options) {
148
- return (0, verify_helpers_1.verifyDisabled)(this.resolveLocator.bind(this), target, options, (0, caller_location_1.getCallerLocation)());
158
+ return (0, verify_helpers_1.verifyDisabled)(this.resolveTarget.bind(this), target, options, (0, caller_location_1.getCallerLocation)());
149
159
  }
150
160
  expect(target, message) {
151
161
  const resolved = typeof target !== 'string' ? target : this.resolveLocator(target);
@@ -1,5 +1,5 @@
1
- import { Locator } from '@playwright/test';
2
- import type { PageKeys, CheckableLocatorKeys, CheckboxLocatorKeys, EditableLocatorKeys, SelectableLocatorKeys, ModifyOptionsForTarget } from '../config';
1
+ import type { Locator } from '@playwright/test';
2
+ import type { ModifyOptionsForTarget, PageKeys } from '../config';
3
3
  export interface ProxyLocatorMethods<T> {
4
4
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-click Locator.click} */
5
5
  click<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['click']>[0]>): Promise<void>;
@@ -12,15 +12,15 @@ export interface ProxyLocatorMethods<T> {
12
12
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-blur Locator.blur} */
13
13
  blur<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['blur']>[0]>): Promise<void>;
14
14
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-check Locator.check} */
15
- check<Target extends CheckableLocatorKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['check']>[0]>): Promise<void>;
15
+ check<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['check']>[0]>): Promise<void>;
16
16
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-uncheck Locator.uncheck} */
17
- uncheck<Target extends CheckboxLocatorKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['uncheck']>[0]>): Promise<void>;
17
+ uncheck<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['uncheck']>[0]>): Promise<void>;
18
18
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-clear Locator.clear} */
19
- clear<Target extends EditableLocatorKeys<T> | (string & {}) | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['clear']>[0]>): Promise<void>;
19
+ clear<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['clear']>[0]>): Promise<void>;
20
20
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-wait-for Locator.waitFor} */
21
21
  waitFor<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['waitFor']>[0]>): Promise<void>;
22
22
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-is-checked Locator.isChecked} */
23
- isChecked<Target extends CheckableLocatorKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['isChecked']>[0]>): Promise<boolean>;
23
+ isChecked<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['isChecked']>[0]>): Promise<boolean>;
24
24
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-is-disabled Locator.isDisabled} */
25
25
  isDisabled<Target extends PageKeys<T> | Locator>(target: Target, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['isDisabled']>[0]>): Promise<boolean>;
26
26
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-is-visible Locator.isVisible} */
@@ -45,29 +45,21 @@ export interface ProxyLocatorMethods<T> {
45
45
  height: number;
46
46
  } | null>;
47
47
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-press Locator.press} */
48
- press<Target extends EditableLocatorKeys<T> | (string & {}) | Locator>(target: Target, key: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['press']>[1]>): Promise<void>;
48
+ press<Target extends PageKeys<T> | Locator>(target: Target, key: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['press']>[1]>): Promise<void>;
49
49
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-press-sequentially Locator.pressSequentially} */
50
- pressSequentially<Target extends EditableLocatorKeys<T> | (string & {}) | Locator>(target: Target, value: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['pressSequentially']>[1]>): Promise<void>;
50
+ pressSequentially<Target extends PageKeys<T> | Locator>(target: Target, value: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['pressSequentially']>[1]>): Promise<void>;
51
51
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-select-option Locator.selectOption} */
52
- selectOption<Target extends SelectableLocatorKeys<T> | (string & {}) | Locator>(target: Target, values: string | string[] | {
52
+ selectOption<Target extends PageKeys<T> | Locator>(target: Target, values: string | string[] | {
53
53
  value?: string;
54
54
  label?: string;
55
55
  index?: number;
56
56
  } | null, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['selectOption']>[1]>): Promise<string[]>;
57
57
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-set-input-files Locator.setInputFiles} */
58
- setInputFiles<Target extends PageKeys<T> | Locator>(target: Target, files: string | string[] | {
59
- name: string;
60
- mimeType: string;
61
- buffer: Buffer;
62
- } | {
63
- name: string;
64
- mimeType: string;
65
- buffer: Buffer;
66
- }[], options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['setInputFiles']>[1]>): Promise<void>;
58
+ setInputFiles<Target extends PageKeys<T> | Locator>(target: Target, files: Parameters<Locator['setInputFiles']>[0], options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['setInputFiles']>[1]>): Promise<void>;
67
59
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-get-attribute Locator.getAttribute} */
68
60
  getAttribute<Target extends PageKeys<T> | Locator>(target: Target, name: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['getAttribute']>[1]>): Promise<string | null>;
69
61
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-fill Locator.fill} */
70
- fill<Target extends EditableLocatorKeys<T> | (string & {}) | Locator>(target: Target, value: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['fill']>[1]> & {
62
+ fill<Target extends PageKeys<T> | Locator>(target: Target, value: string, options?: ModifyOptionsForTarget<T, Target, Parameters<Locator['fill']>[1]> & {
71
63
  mask?: boolean;
72
64
  }): Promise<void>;
73
65
  /** @see {@link https://playwright.dev/docs/api/class-locator#locator-drag-to Locator.dragTo} */
@@ -10,7 +10,7 @@ export type HasDuplicatePlaceholders<S extends string, Seen extends string = nev
10
10
  * Returns the subset of `Placeholders` whose names are NOT found as
11
11
  * substrings of `TestId`. Evaluates to `never` when all are present.
12
12
  */
13
- export type MissingInTestId<TestId extends string, Placeholders extends string> = Placeholders extends any ? TestId extends `${string}${Placeholders}${string}` ? never : Placeholders : never;
13
+ export type MissingInTestId<TestId extends string, Placeholders extends string> = Placeholders extends unknown ? TestId extends `${string}${Placeholders}${string}` ? never : Placeholders : never;
14
14
  /**
15
15
  * Validates a dynamic entry by mapping each of its properties to their expected types.
16
16
  *
@@ -1,3 +1,3 @@
1
- export declare function formatTarget(target: any): string;
2
- export declare function formatStepDescription(methodName: string, target: any, args: any[]): string;
3
- export declare function formatAssertionDescription(target: any, matcherName: string, isNegated: boolean, args: any[]): string;
1
+ export declare function formatTarget(target: unknown): string;
2
+ export declare function formatStepDescription(methodName: string, target: unknown, args: readonly unknown[]): string;
3
+ export declare function formatAssertionDescription(target: unknown, matcherName: string, isNegated: boolean, args: readonly unknown[]): string;
@@ -3,10 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.formatTarget = formatTarget;
4
4
  exports.formatStepDescription = formatStepDescription;
5
5
  exports.formatAssertionDescription = formatAssertionDescription;
6
+ function isStringifiable(value) {
7
+ return typeof value === 'object' && value !== null && typeof value.toString === 'function';
8
+ }
6
9
  function formatTarget(target) {
7
10
  if (typeof target === 'string')
8
11
  return target;
9
- if (target && typeof target.toString === 'function') {
12
+ if (isStringifiable(target)) {
10
13
  return target.toString().replace(/^Locator@/, '');
11
14
  }
12
15
  return 'locator';
@@ -16,7 +19,7 @@ function formatStepDescription(methodName, target, args) {
16
19
  if (methodName === 'fill' && args[0] !== undefined) {
17
20
  const options = args[1];
18
21
  let shouldMask = false;
19
- if (options && typeof options === 'object' && options.mask !== undefined) {
22
+ if (options && typeof options === 'object' && 'mask' in options && options.mask !== undefined) {
20
23
  shouldMask = options.mask === true;
21
24
  }
22
25
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pw-core",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "workspaces": [
5
5
  "examples",
6
6
  "create-pw-core"
@@ -53,14 +53,17 @@
53
53
  "scripts": {
54
54
  "build": "node -e \"const fs = require('fs'); fs.rmSync('dist', {recursive:true,force:true})\" && tsc && npm run build --prefix create-pw-core",
55
55
  "prepare": "npm run build",
56
- "test": "npm run test --workspace=pw-core-demo"
56
+ "test": "npm run test --workspace=pw-core-demo",
57
+ "test:unit": "npm run build && node --test tests/unit/*.test.js",
58
+ "test:types": "tsc --noEmit -p tests/types/tsconfig.json",
59
+ "test:codegen": "npm run build && node scripts/verify-codegen.js"
57
60
  },
58
61
  "peerDependencies": {
59
62
  "@playwright/test": "^1.40.0"
60
63
  },
61
64
  "devDependencies": {
62
65
  "@playwright/test": "^1.61.0",
63
- "@types/node": "^20.11.0",
66
+ "@types/node": "^20.19.43",
64
67
  "prettier": "^3.9.4",
65
68
  "rimraf": "^6.0.1",
66
69
  "typescript": "^5.3.3"