pw-core 1.1.0 → 1.2.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 (96) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +777 -0
  4. package/dist/codegen/config/context-weights.d.ts +8 -0
  5. package/dist/codegen/config/context-weights.js +11 -0
  6. package/dist/codegen/config/ignored-attributes.d.ts +1 -0
  7. package/dist/codegen/config/ignored-attributes.js +4 -0
  8. package/dist/codegen/config/ignored-classes.d.ts +1 -0
  9. package/dist/codegen/config/ignored-classes.js +144 -0
  10. package/dist/codegen/config/ignored-values.d.ts +1 -0
  11. package/dist/codegen/config/ignored-values.js +4 -0
  12. package/dist/codegen/config/index.d.ts +29 -0
  13. package/dist/codegen/config/index.js +17 -0
  14. package/dist/codegen/config/strategy-order.d.ts +1 -0
  15. package/dist/codegen/config/strategy-order.js +18 -0
  16. package/dist/codegen/config/weights.d.ts +15 -0
  17. package/dist/codegen/config/weights.js +18 -0
  18. package/dist/codegen/floating-panel/client.d.ts +1 -0
  19. package/dist/codegen/floating-panel/client.js +248 -0
  20. package/dist/codegen/floating-panel/index.d.ts +4 -0
  21. package/dist/codegen/floating-panel/index.js +20 -0
  22. package/dist/codegen/floating-panel/manager.d.ts +19 -0
  23. package/dist/codegen/floating-panel/manager.js +90 -0
  24. package/dist/codegen/floating-panel/template.d.ts +2 -0
  25. package/dist/codegen/floating-panel/template.js +58 -0
  26. package/dist/codegen/floating-panel/types.d.ts +7 -0
  27. package/dist/codegen/floating-panel/types.js +2 -0
  28. package/dist/codegen/generator/action.validator.d.ts +5 -0
  29. package/dist/codegen/generator/action.validator.js +27 -0
  30. package/dist/codegen/generator/index.d.ts +13 -0
  31. package/dist/codegen/generator/index.js +724 -0
  32. package/dist/codegen/generator/locator.restricted.d.ts +36 -0
  33. package/dist/codegen/generator/locator.restricted.js +127 -0
  34. package/dist/codegen/generator/locator.validator.d.ts +8 -0
  35. package/dist/codegen/generator/locator.validator.js +38 -0
  36. package/dist/codegen/hover-tracker/client.d.ts +1 -0
  37. package/dist/codegen/hover-tracker/client.js +75 -0
  38. package/dist/codegen/hover-tracker/index.d.ts +3 -0
  39. package/dist/codegen/hover-tracker/index.js +19 -0
  40. package/dist/codegen/hover-tracker/manager.d.ts +11 -0
  41. package/dist/codegen/hover-tracker/manager.js +28 -0
  42. package/dist/codegen/hover-tracker/types.d.ts +3 -0
  43. package/dist/codegen/hover-tracker/types.js +2 -0
  44. package/dist/codegen/index.d.ts +35 -0
  45. package/dist/codegen/index.js +1147 -0
  46. package/dist/codegen/key-utils.d.ts +23 -0
  47. package/dist/codegen/key-utils.js +68 -0
  48. package/dist/codegen/scorer/base-score.d.ts +1 -0
  49. package/dist/codegen/scorer/base-score.js +7 -0
  50. package/dist/codegen/scorer/context-score.d.ts +2 -0
  51. package/dist/codegen/scorer/context-score.js +27 -0
  52. package/dist/codegen/scorer/index.d.ts +5 -0
  53. package/dist/codegen/scorer/index.js +23 -0
  54. package/dist/codegen/scorer/locator.ranking.d.ts +15 -0
  55. package/dist/codegen/scorer/locator.ranking.js +83 -0
  56. package/dist/codegen/scorer/semantic-score.d.ts +1 -0
  57. package/dist/codegen/scorer/semantic-score.js +47 -0
  58. package/dist/codegen/types.d.ts +35 -0
  59. package/dist/codegen/types.js +2 -0
  60. package/dist/component/table.js +19 -14
  61. package/dist/constants/methods.d.ts +2 -0
  62. package/dist/constants/methods.js +33 -0
  63. package/dist/constants/strategies.d.ts +2 -0
  64. package/dist/constants/strategies.js +47 -0
  65. package/dist/helpers.d.ts +1 -1
  66. package/dist/helpers.js +21 -9
  67. package/dist/page/actions/locator-actions.js +46 -2
  68. package/dist/page/actions/page-actions.d.ts +11 -6
  69. package/dist/page/actions/page-actions.js +12 -12
  70. package/dist/page/assertions/verify-chain.d.ts +39 -32
  71. package/dist/page/assertions/verify-chain.js +21 -6
  72. package/dist/page/assertions/verify-helpers.d.ts +9 -3
  73. package/dist/page/assertions/verify-helpers.js +18 -9
  74. package/dist/page/config.d.ts +126 -38
  75. package/dist/page/config.js +10 -31
  76. package/dist/page/index.d.ts +1 -0
  77. package/dist/page/index.js +1 -0
  78. package/dist/page/locators/dynamic-locator-resolver.d.ts +49 -0
  79. package/dist/page/locators/dynamic-locator-resolver.js +187 -0
  80. package/dist/page/locators/resolver.d.ts +15 -14
  81. package/dist/page/locators/resolver.js +187 -30
  82. package/dist/page/registry.d.ts +51 -12
  83. package/dist/page/registry.js +90 -18
  84. package/dist/page/typed-page.d.ts +33 -28
  85. package/dist/page/typed-page.js +89 -12
  86. package/dist/page/types/proxy-methods.d.ts +69 -54
  87. package/dist/page/types/validation.d.ts +69 -0
  88. package/dist/page/types/validation.js +2 -0
  89. package/dist/page/utils/caller-location.d.ts +5 -0
  90. package/dist/page/utils/caller-location.js +82 -0
  91. package/dist/page/utils/formatter.js +14 -4
  92. package/dist/types/methods.d.ts +4 -0
  93. package/dist/types/methods.js +2 -0
  94. package/dist/types/strategies.d.ts +17 -0
  95. package/dist/types/strategies.js +2 -0
  96. package/package.json +8 -1
@@ -5,6 +5,7 @@ exports.defineActionMethods = defineActionMethods;
5
5
  const test_1 = require("@playwright/test");
6
6
  const config_1 = require("../config");
7
7
  const formatter_1 = require("../utils/formatter");
8
+ const caller_location_1 = require("../utils/caller-location");
8
9
  function executeAction(prop, resolveLocatorFn, timeout, args) {
9
10
  const [locatorKey, ...methodArgs] = args;
10
11
  let optNth = undefined;
@@ -22,7 +23,13 @@ function executeAction(prop, resolveLocatorFn, timeout, args) {
22
23
  }
23
24
  }
24
25
  const isCount = prop === 'count';
25
- const locator = resolveLocatorFn(locatorKey, { nth: optNth, hasText: optHasText, raw: isCount });
26
+ const userOptions = optionsIndex !== -1 && methodArgs.length > optionsIndex ? methodArgs[optionsIndex] : undefined;
27
+ const locator = resolveLocatorFn(locatorKey, {
28
+ nth: optNth,
29
+ hasText: optHasText,
30
+ raw: isCount,
31
+ ...userOptions
32
+ });
26
33
  const method = locator[prop];
27
34
  if (typeof method !== 'function') {
28
35
  throw new Error(`Property '${prop}' does not exist on Locator.`);
@@ -30,6 +37,13 @@ function executeAction(prop, resolveLocatorFn, timeout, args) {
30
37
  if (prop === 'dragTo' && methodArgs.length > 0) {
31
38
  methodArgs[0] = resolveLocatorFn(methodArgs[0]);
32
39
  }
40
+ if (optionsIndex !== -1 && methodArgs.length > optionsIndex) {
41
+ const opts = methodArgs[optionsIndex];
42
+ if (opts && typeof opts === 'object') {
43
+ const { exact, checked, disabled, expanded, includeHidden, level, pressed, selected, ...rest } = opts;
44
+ methodArgs[optionsIndex] = rest;
45
+ }
46
+ }
33
47
  if (timeout !== undefined) {
34
48
  if (optionsIndex !== -1) {
35
49
  while (methodArgs.length < optionsIndex) {
@@ -47,9 +61,39 @@ function executeAction(prop, resolveLocatorFn, timeout, args) {
47
61
  methodArgs[1] = playwrightOpts;
48
62
  }
49
63
  }
64
+ let shouldMask = false;
65
+ if (prop === 'fill' && methodArgs.length > 0) {
66
+ const opts = methodArgs[1];
67
+ if (opts && typeof opts === 'object' && opts.mask !== undefined) {
68
+ shouldMask = opts.mask === true;
69
+ }
70
+ else {
71
+ const targetStr = (0, formatter_1.formatTarget)(locatorKey);
72
+ const targetStrLower = targetStr.toLowerCase();
73
+ shouldMask = targetStrLower.includes('pass') || targetStrLower.includes('pw');
74
+ }
75
+ }
76
+ if (prop === 'fill' && shouldMask) {
77
+ return test_1.test.step(stepName, async () => {
78
+ await locator.focus();
79
+ await locator.evaluate((el, val) => {
80
+ const inputEl = el;
81
+ const prototype = el.tagName === 'TEXTAREA' ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype;
82
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, 'value');
83
+ if (descriptor && descriptor.set) {
84
+ descriptor.set.call(inputEl, val);
85
+ }
86
+ else {
87
+ inputEl.value = val;
88
+ }
89
+ inputEl.dispatchEvent(new Event('input', { bubbles: true }));
90
+ inputEl.dispatchEvent(new Event('change', { bubbles: true }));
91
+ }, methodArgs[0]);
92
+ }, { box: true, location: (0, caller_location_1.getCallerLocation)() });
93
+ }
50
94
  return test_1.test.step(stepName, () => {
51
95
  return method.apply(locator, methodArgs);
52
- });
96
+ }, { box: true, location: (0, caller_location_1.getCallerLocation)() });
53
97
  }
54
98
  function defineActionMethods(instance, resolveLocatorFn, timeout) {
55
99
  const locatorMethods = [...config_1.zeroArgMethodsList, ...config_1.oneArgMethodsList];
@@ -6,34 +6,39 @@ type GotoOptions = {
6
6
  };
7
7
  type ToHaveURLOptions = Parameters<ReturnType<typeof playwrightExpect<Page>>['toHaveURL']>[1];
8
8
  type ToHaveTitleOptions = Parameters<ReturnType<typeof playwrightExpect<Page>>['toHaveTitle']>[1];
9
+ type StepLocation = {
10
+ file: string;
11
+ line: number;
12
+ column: number;
13
+ };
9
14
  /**
10
15
  * Navigate to the page URL defined in the page config.
11
16
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-goto Page.goto} in a test step.
12
17
  */
13
- export declare function goto(page: Page, url: string | undefined, constructorName: string, options?: GotoOptions): Promise<void>;
18
+ export declare function goto(page: Page, url: string | undefined, constructorName: string, options?: GotoOptions, location?: StepLocation): Promise<void>;
14
19
  /**
15
20
  * Assert the current URL matches the page config URL or a custom pattern.
16
21
  * Uses {@link https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-url expect(page).toHaveURL}.
17
22
  */
18
- export declare function verifyURL(page: Page, url: string | undefined, constructorName: string, urlOrOptions?: string | RegExp | ToHaveURLOptions, options?: ToHaveURLOptions): Promise<void>;
23
+ export declare function verifyURL(page: Page, url: string | undefined, constructorName: string, urlOrOptions?: string | RegExp | ToHaveURLOptions, options?: ToHaveURLOptions, location?: StepLocation): Promise<void>;
19
24
  /**
20
25
  * Assert the page title matches the expected value.
21
26
  * Uses {@link https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-title expect(page).toHaveTitle}.
22
27
  */
23
- export declare function verifyTitle(page: Page, title: string | RegExp, options?: ToHaveTitleOptions): Promise<void>;
28
+ export declare function verifyTitle(page: Page, title: string | RegExp, options?: ToHaveTitleOptions, location?: StepLocation): Promise<void>;
24
29
  /**
25
30
  * Reload the page.
26
31
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-reload Page.reload} in a test step.
27
32
  */
28
- export declare function reload(page: Page, options?: Parameters<Page['reload']>[0]): Promise<void>;
33
+ export declare function reload(page: Page, options?: Parameters<Page['reload']>[0], location?: StepLocation): Promise<void>;
29
34
  /**
30
35
  * Wait for the page to reach a load state.
31
36
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-wait-for-load-state Page.waitForLoadState} in a test step.
32
37
  */
33
- export declare function waitForLoadState(page: Page, state?: Parameters<Page['waitForLoadState']>[0], options?: Parameters<Page['waitForLoadState']>[1]): Promise<void>;
38
+ export declare function waitForLoadState(page: Page, state?: Parameters<Page['waitForLoadState']>[0], options?: Parameters<Page['waitForLoadState']>[1], location?: StepLocation): Promise<void>;
34
39
  /**
35
40
  * Wait for navigation to a URL. Defaults to the page config URL when no pattern is given.
36
41
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-wait-for-url Page.waitForURL} in a test step.
37
42
  */
38
- export declare function waitForURL(page: Page, url: string | undefined, constructorName: string, urlOrOptions?: string | RegExp | Parameters<Page['waitForURL']>[1], options?: Parameters<Page['waitForURL']>[1]): Promise<void>;
43
+ export declare function waitForURL(page: Page, url: string | undefined, constructorName: string, urlOrOptions?: string | RegExp | Parameters<Page['waitForURL']>[1], options?: Parameters<Page['waitForURL']>[1], location?: StepLocation): Promise<void>;
39
44
  export {};
@@ -33,59 +33,59 @@ function resolveUrlPattern(url, constructorName, urlOrOptions, options) {
33
33
  * Navigate to the page URL defined in the page config.
34
34
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-goto Page.goto} in a test step.
35
35
  */
36
- async function goto(page, url, constructorName, options) {
36
+ async function goto(page, url, constructorName, options, location) {
37
37
  await test_1.test.step(`Goto "${url || ''}"`, async () => {
38
38
  if (!url) {
39
39
  throw new Error(`URL is not defined on ${constructorName}`);
40
40
  }
41
41
  await page.goto(url, options);
42
- });
42
+ }, { box: true, location });
43
43
  }
44
44
  /**
45
45
  * Assert the current URL matches the page config URL or a custom pattern.
46
46
  * Uses {@link https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-url expect(page).toHaveURL}.
47
47
  */
48
- async function verifyURL(page, url, constructorName, urlOrOptions, options) {
48
+ async function verifyURL(page, url, constructorName, urlOrOptions, options, location) {
49
49
  const { targetUrl, actualOptions } = resolveUrlPattern(url, constructorName, urlOrOptions, options);
50
50
  const stepName = `Verify URL matches "${targetUrl.toString()}"`;
51
51
  await test_1.test.step(stepName, async () => {
52
52
  await (0, test_1.expect)(page).toHaveURL(targetUrl, actualOptions);
53
- });
53
+ }, { box: true, location });
54
54
  }
55
55
  /**
56
56
  * Assert the page title matches the expected value.
57
57
  * Uses {@link https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-title expect(page).toHaveTitle}.
58
58
  */
59
- async function verifyTitle(page, title, options) {
59
+ async function verifyTitle(page, title, options, location) {
60
60
  const stepName = `Verify title matches "${title}"`;
61
61
  await test_1.test.step(stepName, async () => {
62
62
  await (0, test_1.expect)(page).toHaveTitle(title, options);
63
- });
63
+ }, { box: true, location });
64
64
  }
65
65
  /**
66
66
  * Reload the page.
67
67
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-reload Page.reload} in a test step.
68
68
  */
69
- async function reload(page, options) {
69
+ async function reload(page, options, location) {
70
70
  await test_1.test.step('Reload page', async () => {
71
71
  await page.reload(options);
72
- });
72
+ }, { box: true, location });
73
73
  }
74
74
  /**
75
75
  * Wait for the page to reach a load state.
76
76
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-wait-for-load-state Page.waitForLoadState} in a test step.
77
77
  */
78
- async function waitForLoadState(page, state, options) {
78
+ async function waitForLoadState(page, state, options, location) {
79
79
  const stepName = `Wait for load state "${state ?? 'load'}"`;
80
80
  await test_1.test.step(stepName, async () => {
81
81
  await page.waitForLoadState(state, options);
82
- });
82
+ }, { box: true, location });
83
83
  }
84
84
  /**
85
85
  * Wait for navigation to a URL. Defaults to the page config URL when no pattern is given.
86
86
  * Wraps {@link https://playwright.dev/docs/api/class-page#page-wait-for-url Page.waitForURL} in a test step.
87
87
  */
88
- async function waitForURL(page, url, constructorName, urlOrOptions, options) {
88
+ async function waitForURL(page, url, constructorName, urlOrOptions, options, location) {
89
89
  let targetUrl;
90
90
  let actualOptions = options;
91
91
  if (urlOrOptions !== undefined && (typeof urlOrOptions === 'string' || urlOrOptions instanceof RegExp)) {
@@ -103,5 +103,5 @@ async function waitForURL(page, url, constructorName, urlOrOptions, options) {
103
103
  const stepName = `Wait for URL "${targetUrl.toString()}"`;
104
104
  await test_1.test.step(stepName, async () => {
105
105
  await page.waitForURL(targetUrl, actualOptions);
106
- });
106
+ }, { box: true, location });
107
107
  }
@@ -1,5 +1,5 @@
1
1
  import { Locator, expect as playwrightExpect } from '@playwright/test';
2
- import { ChainedKeys, PageKeys } from '../config';
2
+ import { PageKeys, GetStrategyOfKey } from '../config';
3
3
  export type VerifyOptions = {
4
4
  timeout?: number;
5
5
  nth?: number;
@@ -11,64 +11,71 @@ type ModifyMatcherArgs<Args extends any[]> = Args extends [] ? [options?: {
11
11
  nth?: number;
12
12
  hasText?: string | RegExp;
13
13
  message?: string;
14
- }] : Args extends [any, any?] ? [Args[0], (Exclude<Args[1], undefined> & {
15
- nth?: number;
16
- hasText?: string | RegExp;
17
- message?: string;
18
- })?] : Args extends [any?] ? Exclude<Args[0], undefined> extends object ? [(Exclude<Args[0], undefined> & {
19
- nth?: number;
20
- hasText?: string | RegExp;
21
- message?: string;
22
- })?] : [Exclude<Args[0], undefined>, options?: {
23
- nth?: number;
24
- hasText?: string | RegExp;
25
- message?: string;
26
- }] : [options?: {
27
- nth?: number;
28
- hasText?: string | RegExp;
29
- message?: string;
30
- }];
31
- type DynamicallyModifiedMatchers<T> = {
32
- [K in keyof PlaywrightLocatorMatchers]: K extends 'not' ? Omit<VerifyMatchers<T>, 'not'> : PlaywrightLocatorMatchers[K] extends (...args: infer Args) => any ? (...args: ModifyMatcherArgs<Args>) => Promise<void> : PlaywrightLocatorMatchers[K];
14
+ }] : Args extends [any, any?] ? [
15
+ Args[0],
16
+ (Exclude<Args[1], undefined> & {
17
+ nth?: number;
18
+ hasText?: string | RegExp;
19
+ message?: string;
20
+ })?
21
+ ] : Args extends [any?] ? Exclude<Args[0], undefined> extends object ? [
22
+ (Exclude<Args[0], undefined> & {
23
+ nth?: number;
24
+ hasText?: string | RegExp;
25
+ message?: string;
26
+ })?
27
+ ] : [
28
+ Exclude<Args[0], undefined>,
29
+ options?: {
30
+ nth?: number;
31
+ hasText?: string | RegExp;
32
+ message?: string;
33
+ }
34
+ ] : [
35
+ options?: {
36
+ nth?: number;
37
+ hasText?: string | RegExp;
38
+ message?: string;
39
+ }
40
+ ];
41
+ type DynamicallyModifiedMatchers<T, Target> = {
42
+ [K in keyof PlaywrightLocatorMatchers]: K extends 'not' ? Omit<VerifyMatchers<T, Target>, 'not'> : K extends 'toBeChecked' ? Target extends Locator ? (...args: ModifyMatcherArgs<Parameters<PlaywrightLocatorMatchers[K]>>) => Promise<void> : Target extends string ? GetStrategyOfKey<T, Target> extends 'checkbox' | 'radio' ? (...args: ModifyMatcherArgs<Parameters<PlaywrightLocatorMatchers[K]>>) => Promise<void> : never : never : PlaywrightLocatorMatchers[K] extends (...args: infer Args) => any ? (...args: ModifyMatcherArgs<Args>) => Promise<void> : PlaywrightLocatorMatchers[K];
33
43
  };
34
- export type VerifyMatchers<T> = DynamicallyModifiedMatchers<T> & PromiseLike<void> & {
44
+ export type VerifyMatchers<T, Target> = DynamicallyModifiedMatchers<T, Target> & PromiseLike<void> & {
35
45
  (options?: Parameters<PlaywrightLocatorMatchers['toBeVisible']>[0] & {
36
46
  nth?: number;
37
47
  hasText?: string | RegExp;
38
48
  message?: string;
39
49
  }): Promise<void>;
40
50
  };
41
- export type VerifyFn<T> = (target: PageKeys<T> | ChainedKeys<T> | Locator, options?: VerifyOptions) => VerifyMatchers<T>;
51
+ export type VerifyFn<T> = <Target extends PageKeys<T> | Locator>(target: Target, options?: VerifyOptions) => VerifyMatchers<T, Target>;
42
52
  export type AssertionsMethod<T> = {
43
53
  verify: VerifyFn<T> & {
44
54
  soft: VerifyFn<T>;
45
55
  };
46
- verifyHidden(target: PageKeys<T> | ChainedKeys<T> | Locator, options?: Parameters<ReturnType<typeof playwrightExpect<Locator>>['toBeHidden']>[0] & {
56
+ verifyHidden(target: PageKeys<T> | Locator, options?: Parameters<ReturnType<typeof playwrightExpect<Locator>>['toBeHidden']>[0] & {
47
57
  nth?: number;
48
58
  hasText?: string | RegExp;
49
59
  message?: string;
50
60
  }): Promise<void>;
51
- verifyEnabled(target: PageKeys<T> | ChainedKeys<T> | Locator, options?: Parameters<ReturnType<typeof playwrightExpect<Locator>>['toBeEnabled']>[0] & {
61
+ verifyEnabled(target: PageKeys<T> | Locator, options?: Parameters<ReturnType<typeof playwrightExpect<Locator>>['toBeEnabled']>[0] & {
52
62
  nth?: number;
53
63
  hasText?: string | RegExp;
54
64
  message?: string;
55
65
  }): Promise<void>;
56
- verifyDisabled(target: PageKeys<T> | ChainedKeys<T> | Locator, options?: Parameters<ReturnType<typeof playwrightExpect<Locator>>['toBeDisabled']>[0] & {
66
+ verifyDisabled(target: PageKeys<T> | Locator, options?: Parameters<ReturnType<typeof playwrightExpect<Locator>>['toBeDisabled']>[0] & {
57
67
  nth?: number;
58
68
  hasText?: string | RegExp;
59
69
  message?: string;
60
70
  }): Promise<void>;
61
- expect(target: PageKeys<T> | ChainedKeys<T> | Locator, message?: string): ReturnType<typeof playwrightExpect<Locator>>;
62
- locator(target: PageKeys<T> | ChainedKeys<T> | Locator, options?: Parameters<Locator['filter']>[0] & {
71
+ expect(target: PageKeys<T> | Locator, message?: string): ReturnType<typeof playwrightExpect<Locator>>;
72
+ locator(target: PageKeys<T> | Locator, options?: Parameters<Locator['filter']>[0] & {
63
73
  nth?: number;
64
74
  }): Locator;
65
75
  };
66
- export declare function createVerifyChain<T extends {
67
- testIds?: Record<string, string>;
68
- selectors?: Record<string, string>;
69
- }>(resolveLocator: (target: any, options?: {
76
+ export declare function createVerifyChain<T>(resolveLocator: (target: any, options?: {
70
77
  nth?: number;
71
78
  hasText?: string | RegExp;
72
79
  raw?: boolean;
73
- }) => Locator, target: PageKeys<T> | ChainedKeys<T> | Locator, verifyOptions: VerifyOptions | undefined, isSoft: boolean): VerifyMatchers<T>;
80
+ }) => Locator, target: PageKeys<T> | Locator, verifyOptions: VerifyOptions | undefined, isSoft: boolean): VerifyMatchers<T, any>;
74
81
  export {};
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createVerifyChain = createVerifyChain;
4
4
  const test_1 = require("@playwright/test");
5
5
  const formatter_1 = require("../utils/formatter");
6
+ const caller_location_1 = require("../utils/caller-location");
6
7
  function createVerifyChain(resolveLocator, target, verifyOptions, isSoft) {
7
8
  const defaultNth = verifyOptions?.nth;
8
9
  const defaultHasText = verifyOptions?.hasText;
@@ -18,7 +19,7 @@ function createVerifyChain(resolveLocator, target, verifyOptions, isSoft) {
18
19
  const expectation = expectFn(locator, stepName);
19
20
  const match = isNegated ? expectation.not : expectation;
20
21
  await match.toBeVisible(options);
21
- });
22
+ }, { box: true, location: (0, caller_location_1.getCallerLocation)() });
22
23
  };
23
24
  return new Proxy(baseFn, {
24
25
  get(targetObj, prop) {
@@ -35,7 +36,17 @@ function createVerifyChain(resolveLocator, target, verifyOptions, isSoft) {
35
36
  return baseFn().then(onfulfilled, onrejected);
36
37
  };
37
38
  }
38
- const skippedProps = new Set(['then', 'catch', 'finally', 'bind', 'call', 'apply', 'toString', 'valueOf', 'toLocaleString']);
39
+ const skippedProps = new Set([
40
+ 'then',
41
+ 'catch',
42
+ 'finally',
43
+ 'bind',
44
+ 'call',
45
+ 'apply',
46
+ 'toString',
47
+ 'valueOf',
48
+ 'toLocaleString'
49
+ ]);
39
50
  if (skippedProps.has(prop)) {
40
51
  return targetObj[prop];
41
52
  }
@@ -44,16 +55,20 @@ function createVerifyChain(resolveLocator, target, verifyOptions, isSoft) {
44
55
  const lastIsOptions = lastArg !== null && typeof lastArg === 'object' && !(lastArg instanceof RegExp) && !Array.isArray(lastArg);
45
56
  const valueArgs = lastIsOptions ? args.slice(0, args.length - 1) : args;
46
57
  const options = lastIsOptions ? lastArg : undefined;
47
- const nth = (options && 'nth' in options) ? options.nth : defaultNth;
48
- const hasText = (options && 'hasText' in options) ? options.hasText : defaultHasText;
58
+ const nth = options && 'nth' in options ? options.nth : defaultNth;
59
+ const hasText = options && 'hasText' in options ? options.hasText : defaultHasText;
49
60
  const isHaveCount = prop === 'toHaveCount';
50
61
  const stepName = options?.message ?? defaultMessage ?? (0, formatter_1.formatAssertionDescription)(target, String(prop), isNegated, valueArgs);
51
62
  await test_1.test.step(stepName, async () => {
52
- const locator = resolveLocator(target, { nth, hasText, raw: isHaveCount });
63
+ const locator = resolveLocator(target, {
64
+ nth,
65
+ hasText,
66
+ raw: isHaveCount
67
+ });
53
68
  const expectation = expectFn(locator, stepName);
54
69
  const match = isNegated ? expectation.not : expectation;
55
70
  await match[prop](...args);
56
- });
71
+ }, { box: true, location: (0, caller_location_1.getCallerLocation)() });
57
72
  };
58
73
  }
59
74
  });
@@ -1,4 +1,9 @@
1
1
  import { Locator, expect as playwrightExpect } from '@playwright/test';
2
+ type StepLocation = {
3
+ file: string;
4
+ line: number;
5
+ column: number;
6
+ };
2
7
  export declare function verifyHidden(resolveLocator: (target: any, options?: {
3
8
  nth?: number;
4
9
  hasText?: string | RegExp;
@@ -7,7 +12,7 @@ export declare function verifyHidden(resolveLocator: (target: any, options?: {
7
12
  nth?: number;
8
13
  hasText?: string | RegExp;
9
14
  message?: string;
10
- }): Promise<void>;
15
+ }, location?: StepLocation): Promise<void>;
11
16
  export declare function verifyEnabled(resolveLocator: (target: any, options?: {
12
17
  nth?: number;
13
18
  hasText?: string | RegExp;
@@ -16,7 +21,7 @@ export declare function verifyEnabled(resolveLocator: (target: any, options?: {
16
21
  nth?: number;
17
22
  hasText?: string | RegExp;
18
23
  message?: string;
19
- }): Promise<void>;
24
+ }, location?: StepLocation): Promise<void>;
20
25
  export declare function verifyDisabled(resolveLocator: (target: any, options?: {
21
26
  nth?: number;
22
27
  hasText?: string | RegExp;
@@ -25,4 +30,5 @@ export declare function verifyDisabled(resolveLocator: (target: any, options?: {
25
30
  nth?: number;
26
31
  hasText?: string | RegExp;
27
32
  message?: string;
28
- }): Promise<void>;
33
+ }, location?: StepLocation): Promise<void>;
34
+ export {};
@@ -5,24 +5,33 @@ exports.verifyEnabled = verifyEnabled;
5
5
  exports.verifyDisabled = verifyDisabled;
6
6
  const test_1 = require("@playwright/test");
7
7
  const formatter_1 = require("../utils/formatter");
8
- async function verifyHidden(resolveLocator, target, options) {
8
+ async function verifyHidden(resolveLocator, target, options, location) {
9
9
  const stepName = options?.message ?? (0, formatter_1.formatAssertionDescription)(target, 'toBeHidden', false, [options]);
10
10
  await test_1.test.step(stepName, async () => {
11
- const locator = resolveLocator(target, { nth: options?.nth, hasText: options?.hasText });
11
+ const locator = resolveLocator(target, {
12
+ nth: options?.nth,
13
+ hasText: options?.hasText
14
+ });
12
15
  await (0, test_1.expect)(locator, stepName).toBeHidden(options);
13
- });
16
+ }, { box: true, location });
14
17
  }
15
- async function verifyEnabled(resolveLocator, target, options) {
18
+ async function verifyEnabled(resolveLocator, target, options, location) {
16
19
  const stepName = options?.message ?? (0, formatter_1.formatAssertionDescription)(target, 'toBeEnabled', false, [options]);
17
20
  await test_1.test.step(stepName, async () => {
18
- const locator = resolveLocator(target, { nth: options?.nth, hasText: options?.hasText });
21
+ const locator = resolveLocator(target, {
22
+ nth: options?.nth,
23
+ hasText: options?.hasText
24
+ });
19
25
  await (0, test_1.expect)(locator, stepName).toBeEnabled(options);
20
- });
26
+ }, { box: true, location });
21
27
  }
22
- async function verifyDisabled(resolveLocator, target, options) {
28
+ async function verifyDisabled(resolveLocator, target, options, location) {
23
29
  const stepName = options?.message ?? (0, formatter_1.formatAssertionDescription)(target, 'toBeDisabled', false, [options]);
24
30
  await test_1.test.step(stepName, async () => {
25
- const locator = resolveLocator(target, { nth: options?.nth, hasText: options?.hasText });
31
+ const locator = resolveLocator(target, {
32
+ nth: options?.nth,
33
+ hasText: options?.hasText
34
+ });
26
35
  await (0, test_1.expect)(locator, stepName).toBeDisabled(options);
27
- });
36
+ }, { box: true, location });
28
37
  }
@@ -1,51 +1,139 @@
1
- import { Locator, Page } from '@playwright/test';
2
- export { ProxyLocatorMethods } from './types/proxy-methods';
3
- export declare const zeroArgMethodsList: readonly ["click", "dblclick", "hover", "focus", "blur", "check", "uncheck", "clear", "waitFor", "isChecked", "isDisabled", "isVisible", "textContent", "innerText", "allInnerTexts", "allTextContents", "count", "scrollIntoViewIfNeeded", "boundingBox"];
4
- export declare const oneArgMethodsList: readonly ["fill", "press", "pressSequentially", "selectOption", "setInputFiles", "getAttribute", "dragTo"];
5
- export type AllowedZeroArgMethods = typeof zeroArgMethodsList[number];
6
- export type AllowedOneArgMethods = typeof oneArgMethodsList[number];
7
- export type AllowedMethodKeys = AllowedZeroArgMethods | AllowedOneArgMethods;
1
+ import { Locator } from '@playwright/test';
2
+ import type { DynamicTestIdEntry, DynamicSelectorEntry } from './locators/dynamic-locator-resolver.js';
3
+ export { ProxyLocatorMethods } from './types/proxy-methods.js';
4
+ export type { DynamicLocatorEntry, DynamicTestIdEntry, DynamicSelectorEntry } from './locators/dynamic-locator-resolver.js';
5
+ import { AllowedMethodKeys } from '../types/methods';
6
+ import { StrategyType, LocatorStrategyOptions } from '../types/strategies';
7
+ import { ResolvedTestIdKeys, ValidateTestIds } from './types/validation.js';
8
+ export { zeroArgMethodsList, oneArgMethodsList } from '../constants/methods';
9
+ export { rolesList, strategyList } from '../constants/strategies';
10
+ export { AllowedZeroArgMethods, AllowedOneArgMethods, AllowedMethodKeys } from '../types/methods';
11
+ export { RoleType, StrategyType, PlaywrightRoleOptions, PlaywrightTextOptions, LocatorStrategyOptions } from '../types/strategies';
12
+ export type GetStrategyOfKey<T, K extends string> = K extends (T extends {
13
+ testId: infer I;
14
+ } ? ResolvedTestIdKeys<I> : never) ? 'testId' : K extends (T extends {
15
+ testIds: infer I;
16
+ } ? ResolvedTestIdKeys<I> : never) ? 'testId' : K extends (T extends {
17
+ selector: infer S;
18
+ } ? ResolvedTestIdKeys<S> : never) ? 'selector' : K extends (T extends {
19
+ selectors: infer S;
20
+ } ? ResolvedTestIdKeys<S> : never) ? 'selector' : {
21
+ [S in Exclude<StrategyType, 'testId' | 'selector'>]: K extends (T extends Record<S, readonly string[]> ? T[S][number] : never) ? S : never;
22
+ }[Exclude<StrategyType, 'testId' | 'selector'>];
23
+ export type ModifyOptionsForTarget<T, Target, Options> = Options & {
24
+ nth?: number;
25
+ hasText?: string | RegExp;
26
+ } & (Target extends string ? LocatorStrategyOptions<GetStrategyOfKey<T, Target>> : {});
8
27
  export type PageKeys<T> = (T extends {
9
- testIds?: infer I;
10
- } ? keyof I & string : never) | (T extends {
11
- selectors?: infer S;
12
- } ? keyof S & string : never);
28
+ testId: infer I;
29
+ } ? (I extends Record<string, any> ? ResolvedTestIdKeys<I> : never) : never) | (T extends {
30
+ testIds: infer I;
31
+ } ? (I extends Record<string, any> ? ResolvedTestIdKeys<I> : never) : never) | (T extends {
32
+ selector: infer S;
33
+ } ? (S extends Record<string, any> ? ResolvedTestIdKeys<S> : never) : never) | (T extends {
34
+ selectors: infer S;
35
+ } ? (S extends Record<string, any> ? ResolvedTestIdKeys<S> : never) : never) | {
36
+ [S in Exclude<StrategyType, 'testId' | 'selector'>]: T extends Record<S, readonly string[]> ? T[S][number] : never;
37
+ }[Exclude<StrategyType, 'testId' | 'selector'>];
38
+ export type CheckableLocatorKeys<T> = {
39
+ [S in 'checkbox' | 'radio']: T extends Record<S, readonly string[]> ? T[S][number] : never;
40
+ }['checkbox' | 'radio'];
41
+ export type CheckboxLocatorKeys<T> = T extends Record<'checkbox', readonly string[]> ? T['checkbox'][number] : never;
42
+ export type EditableLocatorKeys<T> = {
43
+ [S in 'label' | 'placeholder' | 'textbox' | 'searchbox']: T extends Record<S, readonly string[]> ? T[S][number] : never;
44
+ }['label' | 'placeholder' | 'textbox' | 'searchbox'];
45
+ export type SelectableLocatorKeys<T> = {
46
+ [S in 'combobox' | 'listbox' | 'option']: T extends Record<S, readonly string[]> ? T[S][number] : never;
47
+ }['combobox' | 'listbox' | 'option'];
13
48
  export type TypedLocators<T> = {
14
49
  [K in PageKeys<T>]: Locator;
15
50
  };
16
- export type ChainedKeys<T> = `${PageKeys<T>}.${PageKeys<T>}`;
51
+ export type UniversalKeys<T> = (T extends {
52
+ testId: infer I;
53
+ } ? ResolvedTestIdKeys<I> : never) | (T extends {
54
+ testIds: infer I;
55
+ } ? ResolvedTestIdKeys<I> : never) | (T extends {
56
+ selector: infer S;
57
+ } ? ResolvedTestIdKeys<S> : never) | (T extends {
58
+ selectors: infer S;
59
+ } ? ResolvedTestIdKeys<S> : never);
60
+ export type SemanticKeys<T> = Exclude<PageKeys<T>, UniversalKeys<T>>;
61
+ export type ChainedKeys<T> = `${UniversalKeys<T>}.${PageKeys<T>}` | `${UniversalKeys<T>}.${SemanticKeys<T>}.${UniversalKeys<T>}` | `${UniversalKeys<T>}.${UniversalKeys<T>}.${PageKeys<T>}`;
17
62
  export type TargetKey<T> = PageKeys<T> | ChainedKeys<T> | Locator;
18
- export type ValidateTarget<K, T> = K extends Locator ? Locator : K extends (PageKeys<T> | ChainedKeys<T>) ? K : never;
63
+ export type ValidateTarget<K, T> = K extends Locator ? Locator : K extends PageKeys<T> | ChainedKeys<T> ? K : never;
19
64
  export declare function getOptionsArgumentIndex(methodName: AllowedMethodKeys): number;
20
- export type PageConfig<T = any> = {
65
+ /** Map type accepted by the `testId` property in a page config. */
66
+ export type TestIdMap = Record<string, string | DynamicTestIdEntry>;
67
+ export type SelectorMap = Record<string, string | DynamicSelectorEntry>;
68
+ export type PageConfig = {
21
69
  url?: string;
22
- testIds?: Record<string, string>;
23
- selectors?: T extends {
70
+ testId?: TestIdMap;
71
+ selector?: SelectorMap;
72
+ testIds?: TestIdMap;
73
+ selectors?: SelectorMap;
74
+ } & {
75
+ [S in Exclude<StrategyType, 'testId' | 'selector'>]?: readonly string[];
76
+ };
77
+ export type KeysOfStrategy<T, S extends StrategyType> = S extends 'testId' ? T extends {
78
+ testId: infer I;
79
+ } ? ResolvedTestIdKeys<I> : T extends {
80
+ testIds: infer I;
81
+ } ? ResolvedTestIdKeys<I> : never : S extends 'selector' ? T extends {
82
+ selector: infer I;
83
+ } ? ResolvedTestIdKeys<I> : T extends {
84
+ selectors: infer S2;
85
+ } ? ResolvedTestIdKeys<S2> : never : T extends Record<S, infer A> ? A extends readonly string[] ? A[number] : never : never;
86
+ export type KeysOfOtherStrategies<T, S extends StrategyType> = {
87
+ [O in Exclude<StrategyType, S>]: KeysOfStrategy<T, O>;
88
+ }[Exclude<StrategyType, S>];
89
+ type GetTestIds<T> = T extends {
90
+ testId: infer I;
91
+ } ? (I extends Record<string, any> ? I : {}) : T extends {
92
+ testIds: infer I;
93
+ } ? (I extends Record<string, any> ? I : {}) : {};
94
+ type GetSelectors<T> = T extends {
95
+ selector: infer S;
96
+ } ? (S extends Record<string, any> ? S : {}) : T extends {
97
+ selectors: infer S;
98
+ } ? (S extends Record<string, any> ? S : {}) : {};
99
+ export type ValidatePageConfig<T> = {
100
+ url?: string;
101
+ testId?: T extends {
102
+ testId: infer I;
103
+ } ? I extends Record<string, any> ? ValidateTestIds<I, 'testId', GetSelectors<T>> & {
104
+ [K in keyof I]: K extends KeysOfOtherStrategies<T, 'testId'> ? {
105
+ [P in `Error: Duplicate key "${K & string}" is defined in multiple strategies`]: never;
106
+ } : any;
107
+ } : TestIdMap : TestIdMap;
108
+ testIds?: T extends {
24
109
  testIds: infer I;
110
+ } ? I extends Record<string, any> ? ValidateTestIds<I, 'testId', GetSelectors<T>> & {
111
+ [K in keyof I]: K extends KeysOfOtherStrategies<T, 'testId'> ? {
112
+ [P in `Error: Duplicate key "${K & string}" is defined in multiple strategies`]: never;
113
+ } : any;
114
+ } : TestIdMap : TestIdMap;
115
+ selector?: T extends {
116
+ selector: infer S;
117
+ } ? S extends Record<string, any> ? ValidateTestIds<S, 'selector', GetTestIds<T>> & {
118
+ [K in keyof S]: K extends KeysOfOtherStrategies<T, 'selector'> ? {
119
+ [P in `Error: Duplicate key "${K & string}" is defined in multiple strategies`]: never;
120
+ } : any;
121
+ } : SelectorMap : SelectorMap;
122
+ selectors?: T extends {
25
123
  selectors: infer S;
26
- } ? {
27
- [K in keyof S]: K extends keyof I ? `Duplicate key: ${K & string} already exists in testIds` : S[K];
28
- } : Record<string, string>;
29
- Class?: new (page: Page, config?: any) => any;
124
+ } ? S extends Record<string, any> ? ValidateTestIds<S, 'selector', GetTestIds<T>> & {
125
+ [K in keyof S]: K extends KeysOfOtherStrategies<T, 'selector'> ? {
126
+ [P in `Error: Duplicate key "${K & string}" is defined in multiple strategies`]: never;
127
+ } : any;
128
+ } : SelectorMap : SelectorMap;
129
+ } & {
130
+ [S in Exclude<StrategyType, 'testId' | 'selector'>]?: T extends Record<S, infer A> ? A extends readonly string[] ? {
131
+ [I in keyof A]: A[I] extends string ? A[I] extends KeysOfOtherStrategies<T, S> ? `Error: Duplicate key "${A[I]}" is defined in multiple strategies` : A[I] : A[I];
132
+ } : readonly string[] : readonly string[];
133
+ } & {
134
+ [K in Exclude<keyof T, keyof PageConfig>]: never;
30
135
  };
31
136
  /**
32
137
  * Creates a strongly-typed page configuration object containing URLs, testIds, and CSS selectors.
33
- *
34
- * @example
35
- * ```ts
36
- * import { createPageConfig } from 'pw-core/page';
37
- *
38
- * const config = createPageConfig({
39
- * url: '/login',
40
- * testIds: {
41
- * username: 'username-input',
42
- * password: 'password-input',
43
- * submitBtn: 'login-button',
44
- * },
45
- * selectors: {
46
- * errorAlert: '.alert-danger',
47
- * }
48
- * });
49
- * ```
50
138
  */
51
- export declare function createPageConfig<T extends PageConfig<T>>(config: T): T;
139
+ export declare function createPageConfig<const T extends PageConfig>(config: [T] extends [ValidatePageConfig<T>] ? T : ValidatePageConfig<T>): T;