pomwright 1.5.1 → 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 (119) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +5 -5
  3. package/dist/index.d.mts +75 -970
  4. package/dist/index.d.ts +75 -970
  5. package/dist/index.js +585 -1872
  6. package/dist/index.mjs +598 -1880
  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 -695
  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.get.clone.spec.ts +0 -76
  58. package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
  59. package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
  60. package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
  61. package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
  62. package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
  63. package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
  64. package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
  65. package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
  66. package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
  67. package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -107
  68. package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
  69. package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
  70. package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
  71. package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
  72. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
  73. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
  74. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
  75. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
  76. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
  77. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
  78. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
  79. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
  80. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
  81. package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
  82. package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
  83. package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
  84. package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
  85. package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.typecheck.ts +0 -86
  86. package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
  87. package/intTestV2/tests/step/step.spec.ts +0 -49
  88. package/intTestV2/tests/testApp/color.spec.ts +0 -15
  89. package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
  90. package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
  91. package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
  92. package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
  93. package/pack-build.sh +0 -11
  94. package/pack-test-v2.sh +0 -36
  95. package/playwright.base.ts +0 -42
  96. package/skills/README.md +0 -56
  97. package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
  98. package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
  99. package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
  100. package/skills/pomwright-v2-migration/SKILL.md +0 -63
  101. package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
  102. package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
  103. package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
  104. package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
  105. package/srcV2/fixture/base.fixtures.ts +0 -23
  106. package/srcV2/helpers/navigation.ts +0 -153
  107. package/srcV2/helpers/playwrightReportLogger.ts +0 -196
  108. package/srcV2/helpers/sessionStorage.ts +0 -251
  109. package/srcV2/helpers/stepDecorator.ts +0 -106
  110. package/srcV2/locators/index.ts +0 -15
  111. package/srcV2/locators/locatorQueryBuilder.ts +0 -427
  112. package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
  113. package/srcV2/locators/locatorRegistry.ts +0 -583
  114. package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
  115. package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
  116. package/srcV2/locators/types.ts +0 -256
  117. package/srcV2/locators/utils.ts +0 -309
  118. package/srcV2/locators/v1SchemaTranslator.ts +0 -178
  119. 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
- });