pomwright 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +5 -5
  3. package/dist/index.d.mts +91 -989
  4. package/dist/index.d.ts +91 -989
  5. package/dist/index.js +627 -1887
  6. package/dist/index.mjs +633 -1888
  7. package/package.json +9 -11
  8. package/AGENTS.md +0 -37
  9. package/docs/v1/BaseApi-explanation.md +0 -63
  10. package/docs/v1/BasePage-explanation.md +0 -96
  11. package/docs/v1/LocatorSchema-explanation.md +0 -271
  12. package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
  13. package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
  14. package/docs/v1/get-locator-methods-explanation.md +0 -250
  15. package/docs/v1/intro-to-using-pomwright.md +0 -899
  16. package/docs/v1/sessionStorage-methods-explanation.md +0 -38
  17. package/docs/v1/tips-folder-structure.md +0 -38
  18. package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
  19. package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
  20. package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
  21. package/docs/v2/PageObject.md +0 -293
  22. package/docs/v2/composing-locator-modules.md +0 -93
  23. package/docs/v2/locator-registry.md +0 -693
  24. package/docs/v2/logging.md +0 -168
  25. package/docs/v2/overview.md +0 -515
  26. package/docs/v2/session-storage.md +0 -160
  27. package/index.ts +0 -75
  28. package/intTestV2/.env +0 -0
  29. package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
  30. package/intTestV2/package.json +0 -22
  31. package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
  32. package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
  33. package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
  34. package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
  35. package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
  36. package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
  37. package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
  38. package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
  39. package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
  40. package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
  41. package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
  42. package/intTestV2/playwright.config.ts +0 -54
  43. package/intTestV2/server.js +0 -216
  44. package/intTestV2/test-data/staticPage/index.html +0 -280
  45. package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
  46. package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
  47. package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
  48. package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
  49. package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
  50. package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
  51. package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
  52. package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
  53. package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
  54. package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
  55. package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
  56. package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
  57. package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
  58. package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
  59. package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
  60. package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
  61. package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
  62. package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
  63. package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
  64. package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
  65. package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
  66. package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -66
  67. package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
  68. package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
  69. package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
  70. package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
  71. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
  72. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
  73. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
  74. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
  75. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
  76. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
  77. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
  78. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
  79. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
  80. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
  81. package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
  82. package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
  83. package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
  84. package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
  85. package/intTestV2/tests/step/step.spec.ts +0 -49
  86. package/intTestV2/tests/testApp/color.spec.ts +0 -15
  87. package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
  88. package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
  89. package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
  90. package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
  91. package/pack-build.sh +0 -11
  92. package/pack-test-v2.sh +0 -36
  93. package/playwright.base.ts +0 -42
  94. package/skills/README.md +0 -56
  95. package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
  96. package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
  97. package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
  98. package/skills/pomwright-v2-migration/SKILL.md +0 -63
  99. package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
  100. package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
  101. package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
  102. package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
  103. package/srcV2/fixture/base.fixtures.ts +0 -23
  104. package/srcV2/helpers/navigation.ts +0 -153
  105. package/srcV2/helpers/playwrightReportLogger.ts +0 -196
  106. package/srcV2/helpers/sessionStorage.ts +0 -251
  107. package/srcV2/helpers/stepDecorator.ts +0 -106
  108. package/srcV2/locators/index.ts +0 -15
  109. package/srcV2/locators/locatorQueryBuilder.ts +0 -427
  110. package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
  111. package/srcV2/locators/locatorRegistry.ts +0 -541
  112. package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
  113. package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
  114. package/srcV2/locators/types.ts +0 -256
  115. package/srcV2/locators/utils.ts +0 -309
  116. package/srcV2/locators/v1SchemaTranslator.ts +0 -178
  117. package/srcV2/pageObject.ts +0 -105
@@ -1,32 +0,0 @@
1
- import { expect, test } from "@fixtures-v2/testApp.fixtures";
2
- import type { Page } from "@playwright/test";
3
- import { createRegistryWithAccessors } from "pomwright";
4
-
5
- const createRegistry = <Paths extends string>(page: Page) => createRegistryWithAccessors<Paths>(page);
6
-
7
- test("remove deletes definition and causes resolution to fail", async ({ page }) => {
8
- type Paths = "root" | "root.target";
9
-
10
- const { add, getLocatorSchema } = createRegistry<Paths>(page);
11
-
12
- add("root").locator("div.root");
13
- add("root.target").locator(".child");
14
-
15
- const builder = getLocatorSchema("root.target");
16
- builder.remove("root.target");
17
-
18
- expect(() => builder.getNestedLocator()).toThrowError('No locator schema registered for path "root.target".');
19
- });
20
-
21
- test("remove on non-terminal skips the segment while allowing resolution", async ({ page }) => {
22
- type Paths = "root" | "root.child";
23
-
24
- const { add, getLocatorSchema } = createRegistry<Paths>(page);
25
-
26
- add("root").locator("div.root");
27
- add("root.child").getByRole("button", { name: "Submit" });
28
-
29
- const locator = getLocatorSchema("root.child").remove("root").getNestedLocator();
30
-
31
- expect(`${locator}`).toEqual("getByRole('button', { name: 'Submit' })");
32
- });
@@ -1,24 +0,0 @@
1
- import { expect, test } from "@fixtures-v2/testApp.fixtures";
2
- import type { Page } from "@playwright/test";
3
- import { createRegistryWithAccessors } from "pomwright";
4
-
5
- const createRegistry = <Paths extends string>(page: Page) => createRegistryWithAccessors<Paths>(page);
6
-
7
- test("replace updates definition while retaining recorded steps", async ({ page }) => {
8
- type Paths = "root" | "root.target";
9
-
10
- const { add, getLocatorSchema } = createRegistry<Paths>(page);
11
-
12
- add("root").locator("div.root");
13
- add("root.target").locator(".old").filter({ hasText: "old" });
14
-
15
- const locator = getLocatorSchema("root.target")
16
- .replace("root.target")
17
- .getByRole("button", { name: "New" })
18
- .filter("root.target", { hasText: "patched" })
19
- .getNestedLocator();
20
-
21
- expect(`${locator}`).toEqual(
22
- "locator('div.root').getByRole('button', { name: 'New' }).filter({ hasText: 'old' }).filter({ hasText: 'patched' })",
23
- );
24
- });
@@ -1,110 +0,0 @@
1
- import { expect, test } from "@fixtures-v2/testApp.fixtures";
2
-
3
- test("shorthand getLocator returns the same none-nested locator as getLocatorSchema.getLocator", async ({
4
- testPage,
5
- }) => {
6
- const builderLocator = testPage.getLocatorSchema("topMenu.notifications.dropdown.item").getLocator();
7
- const shorthand = testPage.getLocator("topMenu.notifications.dropdown.item");
8
-
9
- expect(`${shorthand}`).toEqual(`${builderLocator}`);
10
- });
11
-
12
- test("shorthand getNestedLocator returns the same nested locator as getLocatorSchema.getNestedLocator", async ({
13
- testPage,
14
- }) => {
15
- const builderLocator = testPage.getLocatorSchema("topMenu.notifications.dropdown.item").getNestedLocator();
16
- const shorthand = testPage.getNestedLocator("topMenu.notifications.dropdown.item");
17
-
18
- expect(`${shorthand}`).toEqual(`${builderLocator}`);
19
- });
20
-
21
- test("independent builders do not share state", async ({ testFilters }) => {
22
- const modified = testFilters
23
- .getLocatorSchema("body.section.heading")
24
- .update("body.section.heading")
25
- .getByRole({ name: "hello", level: 3, exact: true })
26
- .getNestedLocator();
27
-
28
- const untouched = testFilters.getLocatorSchema("body.section.heading").getNestedLocator();
29
-
30
- expect(`${modified}`).toEqual(
31
- "locator('body').locator('section').getByRole('heading', { name: 'hello', exact: true, level: 3 })",
32
- );
33
- expect(`${untouched}`).toEqual("locator('body').locator('section').getByRole('heading', { level: 2 })");
34
- });
35
-
36
- test("demonstrate filter and index implementation in v2", async ({ page, testFilters }) => {
37
- const schemaTwo = testFilters.getLocatorSchema("one.two");
38
-
39
- const initialLocator = schemaTwo.getNestedLocator();
40
- expect(`${initialLocator}`).toEqual("locator('div.one').locator('div.two').filter({ hasText: 'two' }).first()");
41
-
42
- schemaTwo
43
- .update("one.two")
44
- .locator()
45
- .clearSteps("one.two")
46
- .filter("one.two", { hasText: "NewText" })
47
- .filter("one.two", { hasText: "AdditionalText" })
48
- .nth("one.two", "last");
49
- const newLocator = schemaTwo.getNestedLocator();
50
- expect(`${newLocator}`).toEqual(
51
- "locator('div.one').locator('div.two').filter({ hasText: 'NewText' }).filter({ hasText: 'AdditionalText' }).last()",
52
- );
53
-
54
- schemaTwo
55
- .clearSteps("one.two")
56
- .filter("one.two", { hasText: "NewText" })
57
- .filter("one.two", { hasText: "AdditionalText" })
58
- .filter("one.two", { hasText: "AddedText" })
59
- .filter("one.two", { hasText: "LastText" })
60
- .nth("one", 0)
61
- .nth("one.two", 1);
62
- const updatedLocator = schemaTwo.getNestedLocator();
63
- expect(`${updatedLocator}`).toEqual(
64
- "locator('div.one').first().locator('div.two').filter({ hasText: 'NewText' }).filter({ hasText: 'AdditionalText' }).filter({ hasText: 'AddedText' }).filter({ hasText: 'LastText' }).nth(1)",
65
- );
66
-
67
- // But in vanilla Playwright we can do:
68
-
69
- const manualLocator = page
70
- .locator("div.one")
71
- .locator("div.two")
72
- .first()
73
- .filter({ hasText: "NewText" })
74
- .last()
75
- .filter({ hasText: "AdditionalText" })
76
- .filter({ hasText: "AddedText" })
77
- .filter({ hasText: "LastText" })
78
- .nth(1);
79
- expect(`${manualLocator}`).toEqual(
80
- "locator('div.one').locator('div.two').first().filter({ hasText: 'NewText' }).last().filter({ hasText: 'AdditionalText' }).filter({ hasText: 'AddedText' }).filter({ hasText: 'LastText' }).nth(1)",
81
- );
82
-
83
- const autoChainedLocator = testFilters
84
- .getLocatorSchema("one.two")
85
- .clearSteps("one.two")
86
- .nth("one.two", 0)
87
- .filter("one.two", { hasText: "NewText" })
88
- .nth("one.two", -1)
89
- .filter("one.two", { hasText: "AdditionalText" })
90
- .filter("one.two", { hasText: "AddedText" })
91
- .filter("one.two", { hasText: "LastText" })
92
- .nth("one.two", 1)
93
- .getNestedLocator();
94
-
95
- expect(`${autoChainedLocator}`).toEqual(`${manualLocator}`);
96
-
97
- const autoChainedLocatorWrapper = testFilters
98
- .getLocatorSchema("one.two")
99
- .clearSteps("one.two")
100
- .nth("one.two", 0)
101
- .filter("one.two", { hasText: "NewText" })
102
- .nth("one.two", -1)
103
- .filter("one.two", { hasText: "AdditionalText" })
104
- .filter("one.two", { hasText: "AddedText" })
105
- .filter("one.two", { hasText: "LastText" })
106
- .nth("one.two", 1)
107
- .getNestedLocator();
108
-
109
- expect(`${autoChainedLocatorWrapper}`).toEqual(`${manualLocator}`);
110
- });
@@ -1,322 +0,0 @@
1
- import { expect, test } from "@fixtures-v2/testApp.fixtures";
2
- import { LocatorRegistryInternal } from "../../../../srcV2/locators";
3
-
4
- test("update replaces intermediate definitions without mutating registry", async ({ testFilters }) => {
5
- const original = testFilters.getNestedLocator("body.section.heading");
6
- expect(`${original}`).toEqual("locator('body').locator('section').getByRole('heading', { level: 2 })");
7
-
8
- const replaced = testFilters
9
- .getLocatorSchema("body.section.heading")
10
- .update("body.section")
11
- .getByRole("heading", { level: 1 })
12
- .getNestedLocator();
13
-
14
- expect(`${replaced}`).toEqual(
15
- "locator('body').getByRole('heading', { level: 1 }).getByRole('heading', { level: 2 })",
16
- );
17
-
18
- const after = testFilters.getNestedLocator("body.section.heading");
19
- expect(`${after}`).toEqual(`${original}`);
20
- });
21
-
22
- test("update operations can be chained across sub-paths", async ({ testFilters }) => {
23
- const chained = testFilters
24
- .getLocatorSchema("body.section")
25
- .update("body")
26
- .locator("SOMEBODY")
27
- .update("body.section")
28
- .getByRole("button", { name: "Click me!" })
29
- .getNestedLocator();
30
-
31
- expect(`${chained}`).toEqual("locator('SOMEBODY').getByRole('button', { name: 'Click me!' })");
32
- });
33
-
34
- test("update merges options without requiring full definitions", async ({ testFilters }) => {
35
- const merged = testFilters
36
- .getLocatorSchema("body.section.heading")
37
- .update("body.section.heading")
38
- .getByRole({ name: "HEADING TEXT" })
39
- .getNestedLocator();
40
-
41
- expect(`${merged}`).toEqual(
42
- "locator('body').locator('section').getByRole('heading', { name: 'HEADING TEXT', level: 2 })",
43
- );
44
- });
45
-
46
- test("update handles full and partial definitions from fresh builders", async ({ testFilters }) => {
47
- const full = testFilters
48
- .getLocatorSchema("body.section.heading")
49
- .update("body.section.heading")
50
- .getByRole("heading", { level: 3 })
51
- .getNestedLocator();
52
-
53
- const partial = testFilters
54
- .getLocatorSchema("body.section.heading")
55
- .update("body.section.heading")
56
- .getByRole({ level: 3 })
57
- .getNestedLocator();
58
-
59
- expect(`${full}`).toEqual("locator('body').locator('section').getByRole('heading', { level: 3 })");
60
- expect(`${partial}`).toEqual("locator('body').locator('section').getByRole('heading', { level: 3 })");
61
- expect(full).not.toBe(partial);
62
- });
63
-
64
- test("update preserves registered filters on untouched segments", async ({ testFilters }) => {
65
- const locator = testFilters
66
- .getLocatorSchema("fictional.filter@hasNotText.filter@hasText")
67
- .update("fictional.filter@hasNotText")
68
- .getByRole("button", { name: "roleOptions" })
69
- .update("fictional.filter@hasNotText.filter@hasText")
70
- .locator("locator")
71
- .getNestedLocator();
72
-
73
- expect(`${locator}`).toEqual(
74
- "getByRole('button', { name: 'roleOptions' }).filter({ hasNotText: 'hasNotText' }).locator('locator').filter({ hasText: 'hasText' })",
75
- );
76
- });
77
-
78
- test("update rejects unknown sub-paths", ({ testFilters }) => {
79
- expect(() =>
80
- testFilters
81
- .getLocatorSchema("body.section.heading")
82
- // @ts-expect-error Testing invalid path handling
83
- .update("body.section.missing")
84
- .locator("noop"),
85
- ).toThrow('"body.section.missing" is not a valid sub-path of "body.section.heading"');
86
- });
87
-
88
- test("update can mix ancestor and descendant changes without mutating registry", async ({ testFilters }) => {
89
- const original = testFilters.getNestedLocator("body.section.heading");
90
-
91
- const chained = testFilters
92
- .getLocatorSchema("body.section.heading")
93
- .update("body")
94
- .locator("SOMEBODY")
95
- .update("body.section.heading")
96
- .getByRole({ name: "HEADING TEXT" })
97
- .getNestedLocator();
98
-
99
- expect(`${chained}`).toEqual(
100
- "locator('SOMEBODY').locator('section').getByRole('heading', { name: 'HEADING TEXT', level: 2 })",
101
- );
102
-
103
- const after = testFilters.getNestedLocator("body.section.heading");
104
- expect(`${after}`).toEqual(`${original}`);
105
- });
106
-
107
- test("update preserves filters on the target sub-path", async ({ testFilters }) => {
108
- const locator = testFilters
109
- .getLocatorSchema("fictional.filter@hasText")
110
- .update("fictional.filter@hasText")
111
- .locator("updated")
112
- .getNestedLocator();
113
-
114
- expect(`${locator}`).toEqual("locator('updated').filter({ hasText: 'hasText' })");
115
- });
116
-
117
- test("update patches definitions without altering chained filters or indices", async ({ testFilters }) => {
118
- const updated = testFilters
119
- .getLocatorSchema("body.section.button")
120
- .filter("body.section.button", { hasText: /Click me!/ })
121
- .nth("body.section", "first")
122
- .update("body.section.button")
123
- .getByRole("button", { name: "Click me!" })
124
- .getNestedLocator();
125
-
126
- expect(`${updated}`).toEqual(
127
- "locator('body').locator('section').first().getByRole('button', { name: 'Click me!' }).filter({ hasText: /Click me!/ })",
128
- );
129
-
130
- const untouched = testFilters.getLocatorSchema("body.section.button").getNestedLocator();
131
- expect(`${untouched}`).toEqual("locator('body').locator('section').getByRole('button')");
132
- });
133
-
134
- test("update can remove locator options filters", async ({ testFilters }) => {
135
- const original = testFilters.getNestedLocator("body.section@playground");
136
- expect(`${original}`).toEqual("locator('body').locator('section').filter({ hasText: /Playground/i })");
137
-
138
- const locator = testFilters
139
- .getLocatorSchema("body.section@playground")
140
- .update("body.section@playground")
141
- .locator({ hasText: undefined })
142
- .getNestedLocator();
143
-
144
- expect(`${locator}`).toEqual("locator('body').locator('section')");
145
- });
146
-
147
- test("update can switch locator strategies, caching all latest locator definitions and preserving state of filters and indices", async ({
148
- page,
149
- testFilters,
150
- }) => {
151
- const path = "body.section" as const;
152
- const schema = testFilters.getLocatorSchema(path);
153
-
154
- const initialLocator = schema.getNestedLocator();
155
- expect(`${initialLocator}`).toEqual("locator('body').locator('section')");
156
-
157
- const manualLocator = page.locator("body").locator("newSelector").filter({ hasText: "Text" }).first();
158
- const locator = schema
159
- .update(path)
160
- .locator("newSelector")
161
- .filter(path, { hasText: "Text" })
162
- .nth(path, 0)
163
- .getNestedLocator();
164
- expect(`${locator}`).toEqual(`${manualLocator}`);
165
-
166
- const manualRole = page
167
- .locator("body")
168
- .getByRole("region", { name: "Now a region" })
169
- .filter({ hasText: "Text" })
170
- .first();
171
- const role = schema.update(path).getByRole("region", { name: "Now a region" }).getNestedLocator();
172
- expect(`${role}`).toEqual(`${manualRole}`);
173
-
174
- const manualText = page.locator("body").getByText("Text node").filter({ hasText: "Text" }).first();
175
- const text = schema.update(path).getByText("Text node").getNestedLocator();
176
- expect(`${text}`).toEqual(`${manualText}`);
177
-
178
- const manualLabel = page.locator("body").getByLabel("Label").filter({ hasText: "Text" }).first();
179
- const label = schema.update(path).getByLabel("Label").getNestedLocator();
180
- expect(`${label}`).toEqual(`${manualLabel}`);
181
-
182
- const manualPlaceholder = page.locator("body").getByPlaceholder("Placeholder").filter({ hasText: "Text" }).first();
183
- const placeholder = schema.update(path).getByPlaceholder("Placeholder").getNestedLocator();
184
- expect(`${placeholder}`).toEqual(`${manualPlaceholder}`);
185
-
186
- const manualAltText = page.locator("body").getByAltText("Alt").filter({ hasText: "Text" }).first();
187
- const altText = schema.update(path).getByAltText("Alt").getNestedLocator();
188
- expect(`${altText}`).toEqual(`${manualAltText}`);
189
-
190
- const manualTitle = page.locator("body").getByTitle("Title").filter({ hasText: "Text" }).first();
191
- const title = schema.update(path).getByTitle("Title").getNestedLocator();
192
- expect(`${title}`).toEqual(`${manualTitle}`);
193
-
194
- const manualFrameLocator = page.locator("body").locator("iframe[name=child]");
195
- const frameLocator = schema.update(path).frameLocator("iframe[name=child]").getNestedLocator();
196
- expect(`${frameLocator}`).toEqual(`${manualFrameLocator}`);
197
-
198
- const manualTestId = page.locator("body").getByTestId("new-test-id").filter({ hasText: "Text" }).first();
199
- const testId = schema.update(path).getByTestId("new-test-id").getNestedLocator();
200
- expect(`${testId}`).toEqual(`${manualTestId}`);
201
-
202
- const manualId = page.locator("body").locator("#new-id").filter({ hasText: "Text" }).first();
203
- const id = schema.update(path).getById("new-id").getNestedLocator();
204
- expect(`${id}`).toEqual(`${manualId}`);
205
-
206
- const manualDataCy = page.locator("body").locator('[data-cy="new-cy"]').filter({ hasText: "Text" }).first();
207
- const dataCy = schema.update(path).locator('[data-cy="new-cy"]').getNestedLocator();
208
- expect(`${dataCy}`).toEqual(`${manualDataCy}`);
209
-
210
- const resetLocator = schema.update(path).locator().getNestedLocator();
211
- expect(`${resetLocator}`).toEqual(`${dataCy}`);
212
-
213
- const resetRole = schema.update(path).getByRole().getNestedLocator();
214
- expect(`${resetRole}`).toEqual(`${role}`);
215
-
216
- const resetText = schema.update(path).getByText().getNestedLocator();
217
- expect(`${resetText}`).toEqual(`${text}`);
218
-
219
- const resetLabel = schema.update(path).getByLabel().getNestedLocator();
220
- expect(`${resetLabel}`).toEqual(`${label}`);
221
-
222
- const resetPlaceholder = schema.update(path).getByPlaceholder().getNestedLocator();
223
- expect(`${resetPlaceholder}`).toEqual(`${placeholder}`);
224
-
225
- const resetAltText = schema.update(path).getByAltText().getNestedLocator();
226
- expect(`${resetAltText}`).toEqual(`${altText}`);
227
-
228
- const resetTitle = schema.update(path).getByTitle().getNestedLocator();
229
- expect(`${resetTitle}`).toEqual(`${title}`);
230
-
231
- const resetFrameLocator = schema.update(path).frameLocator().getNestedLocator();
232
- expect(`${resetFrameLocator}`).toEqual(`${frameLocator}`);
233
-
234
- const resetTestId = schema.update(path).getByTestId().getNestedLocator();
235
- expect(`${resetTestId}`).toEqual(`${testId}`);
236
-
237
- const resetId = schema.update(path).getById().getNestedLocator();
238
- expect(`${resetId}`).toEqual(`${id}`);
239
-
240
- const resetLocatorAgain = schema.update(path).locator().getNestedLocator();
241
- expect(`${resetLocatorAgain}`).toEqual(`${dataCy}`);
242
-
243
- const lastRoleClearSteps = schema
244
- .update(path)
245
- .getByRole()
246
- .clearSteps("body")
247
- .clearSteps("body.section")
248
- .getNestedLocator();
249
- expect(`${lastRoleClearSteps}`).toEqual("locator('body').getByRole('region', { name: 'Now a region' })");
250
-
251
- const stillNoFiltersAndIndicesOnAdditionalSwitch = schema.update(path).locator().getNestedLocator();
252
- expect(`${stillNoFiltersAndIndicesOnAdditionalSwitch}`).toEqual("locator('body').locator('[data-cy=\"new-cy\"]')");
253
- });
254
-
255
- test("update getByRole overloads preserve patch semantics without undefined placeholders", async ({ page }) => {
256
- type LocalPath = "overload" | "overload.target";
257
- const registry = new LocatorRegistryInternal<LocalPath>(page);
258
-
259
- registry.add("overload").locator("body");
260
- registry.add("overload.target").getByRole("button", { name: "initial" }).filter({ hasText: "initial" }).nth(0);
261
-
262
- const withRoleAndOptions = await registry
263
- .getLocatorSchema("overload.target")
264
- .update("overload.target")
265
- .getByRole("button", { name: "patched" })
266
- .filter("overload.target", { hasText: "patched" })
267
- .nth("overload.target", "last")
268
- .getNestedLocator();
269
-
270
- expect(`${withRoleAndOptions}`).toContain("getByRole('button', { name: 'patched' })");
271
- expect(`${withRoleAndOptions}`).toContain("filter({ hasText: 'patched' })");
272
- expect(`${withRoleAndOptions}`).toContain("last()");
273
-
274
- const withOptionsOnly = await registry
275
- .getLocatorSchema("overload.target")
276
- .update("overload.target")
277
- .getByRole({ name: "patched" })
278
- .getNestedLocator();
279
-
280
- expect(`${withOptionsOnly}`).toContain("getByRole('button', { name: 'patched' })");
281
- expect(`${withOptionsOnly}`).toContain("filter({ hasText: 'initial' })");
282
- expect(`${withOptionsOnly}`).toContain("first()");
283
- });
284
-
285
- test("update overloads cover multiple strategies and retain filter/index steps", async ({ page }) => {
286
- type LocalPath = "update.text" | "update.locator" | "update.frame";
287
- const registry = new LocatorRegistryInternal<LocalPath>(page);
288
-
289
- registry.add("update.text").getByText("seed");
290
- registry.add("update.locator").locator(".seed");
291
- registry.add("update.frame").frameLocator("iframe[name=seed]");
292
-
293
- const textPatched = await registry
294
- .getLocatorSchema("update.text")
295
- .update("update.text")
296
- .getByText({ exact: true })
297
- .filter("update.text", { hasText: "patched" })
298
- .nth("update.text", 0)
299
- .getNestedLocator();
300
-
301
- expect(`${textPatched}`).toEqual("getByText('seed', { exact: true }).filter({ hasText: 'patched' }).first()");
302
-
303
- const locatorPatched = await registry
304
- .getLocatorSchema("update.locator")
305
- .update("update.locator")
306
- .locator({ hasText: "opt" })
307
- .filter("update.locator", { hasText: "patched" })
308
- .nth("update.locator", 0)
309
- .getNestedLocator();
310
-
311
- expect(`${locatorPatched}`).toEqual(
312
- "locator('.seed').filter({ hasText: 'opt' }).filter({ hasText: 'patched' }).first()",
313
- );
314
-
315
- const framePatched = await registry
316
- .getLocatorSchema("update.frame")
317
- .update("update.frame")
318
- .frameLocator()
319
- .getNestedLocator();
320
-
321
- expect(`${framePatched}`).toEqual("locator('iframe[name=seed]')");
322
- });