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.
- package/CHANGELOG.md +36 -0
- package/README.md +5 -5
- package/dist/index.d.mts +91 -989
- package/dist/index.d.ts +91 -989
- package/dist/index.js +627 -1887
- package/dist/index.mjs +633 -1888
- package/package.json +9 -11
- package/AGENTS.md +0 -37
- package/docs/v1/BaseApi-explanation.md +0 -63
- package/docs/v1/BasePage-explanation.md +0 -96
- package/docs/v1/LocatorSchema-explanation.md +0 -271
- package/docs/v1/LocatorSchemaPath-explanation.md +0 -165
- package/docs/v1/PlaywrightReportLogger-explanation.md +0 -56
- package/docs/v1/get-locator-methods-explanation.md +0 -250
- package/docs/v1/intro-to-using-pomwright.md +0 -899
- package/docs/v1/sessionStorage-methods-explanation.md +0 -38
- package/docs/v1/tips-folder-structure.md +0 -38
- package/docs/v1-to-v2-migration/bridge-migration-guide.md +0 -159
- package/docs/v1-to-v2-migration/direct-migration-guide.md +0 -238
- package/docs/v1-to-v2-migration/v1-to-v2-comparison.md +0 -547
- package/docs/v2/PageObject.md +0 -293
- package/docs/v2/composing-locator-modules.md +0 -93
- package/docs/v2/locator-registry.md +0 -693
- package/docs/v2/logging.md +0 -168
- package/docs/v2/overview.md +0 -515
- package/docs/v2/session-storage.md +0 -160
- package/index.ts +0 -75
- package/intTestV2/.env +0 -0
- package/intTestV2/fixtures/testApp.fixtures.ts +0 -43
- package/intTestV2/package.json +0 -22
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.locatorSchema.ts +0 -24
- package/intTestV2/page-object-models/testApp/pages/iframe/iframe.page.ts +0 -17
- package/intTestV2/page-object-models/testApp/pages/testPage.locatorSchema.ts +0 -32
- package/intTestV2/page-object-models/testApp/pages/testPage.page.ts +0 -119
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.locatorSchema.ts +0 -29
- package/intTestV2/page-object-models/testApp/pages/testPath/[color]/color.page.ts +0 -48
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.locatorSchema.ts +0 -9
- package/intTestV2/page-object-models/testApp/pages/testPath/testPath.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.locatorSchema.ts +0 -114
- package/intTestV2/page-object-models/testApp/pages/testfilters/testfilters.page.ts +0 -23
- package/intTestV2/page-object-models/testApp/testApp.base.ts +0 -20
- package/intTestV2/playwright.config.ts +0 -54
- package/intTestV2/server.js +0 -216
- package/intTestV2/test-data/staticPage/index.html +0 -280
- package/intTestV2/test-data/staticPage/w3images/avatar2.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar3.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar5.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/avatar6.png +0 -0
- package/intTestV2/test-data/staticPage/w3images/forest.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/lights.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/mountains.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/nature.jpg +0 -0
- package/intTestV2/test-data/staticPage/w3images/snow.jpg +0 -0
- package/intTestV2/tests/locatorRegistry/add/add.describe.spec.ts +0 -54
- package/intTestV2/tests/locatorRegistry/add/add.filter.spec.ts +0 -143
- package/intTestV2/tests/locatorRegistry/add/add.frameLocator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByAltText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getById.spec.ts +0 -45
- package/intTestV2/tests/locatorRegistry/add/add.getByLabel.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByPlaceholder.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByRole.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTestId.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByText.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.getByTitle.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.locator.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/add/add.reuseExisting.spec.ts +0 -66
- package/intTestV2/tests/locatorRegistry/add/add.reuseReusable.spec.ts +0 -311
- package/intTestV2/tests/locatorRegistry/add/add.spec.ts +0 -159
- package/intTestV2/tests/locatorRegistry/filter.cycle.spec.ts +0 -39
- package/intTestV2/tests/locatorRegistry/getLocator/getLocator.spec.ts +0 -253
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.clearSteps.spec.ts +0 -105
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.describe.spec.ts +0 -23
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.filter.spec.ts +0 -368
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getLocator.spec.ts +0 -56
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.getNestedLocator.spec.ts +0 -175
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.nth.spec.ts +0 -60
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.remove.spec.ts +0 -32
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.replace.spec.ts +0 -24
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.spec.ts +0 -110
- package/intTestV2/tests/locatorRegistry/getLocatorSchema/getLocatorSchema.update.spec.ts +0 -322
- package/intTestV2/tests/locatorRegistry/getNestedLocator/getNestedLocator.spec.ts +0 -412
- package/intTestV2/tests/locatorRegistry/registry/registry.binding.spec.ts +0 -50
- package/intTestV2/tests/locatorRegistry/validation/validation.locatorSchemaPath.spec.ts +0 -115
- package/intTestV2/tests/locatorRegistry/validation/validation.sub-path.spec.ts +0 -45
- package/intTestV2/tests/step/step.spec.ts +0 -49
- package/intTestV2/tests/testApp/color.spec.ts +0 -15
- package/intTestV2/tests/testApp/iframe.spec.ts +0 -57
- package/intTestV2/tests/testApp/testFilters.spec.ts +0 -24
- package/intTestV2/tests/testApp/testPage.spec.ts +0 -161
- package/intTestV2/tests/testApp/testPath.spec.ts +0 -18
- package/pack-build.sh +0 -11
- package/pack-test-v2.sh +0 -36
- package/playwright.base.ts +0 -42
- package/skills/README.md +0 -56
- package/skills/pomwright-v1-5-bridge-migration/SKILL.md +0 -40
- package/skills/pomwright-v1-5-bridge-migration/references/call-site-migration.md +0 -178
- package/skills/pomwright-v1-5-bridge-migration/references/schema-translation.md +0 -183
- package/skills/pomwright-v2-migration/SKILL.md +0 -63
- package/skills/pomwright-v2-migration/references/call-site-migration.md +0 -265
- package/skills/pomwright-v2-migration/references/class-migration.md +0 -266
- package/skills/pomwright-v2-migration/references/fixture-and-helpers.md +0 -423
- package/skills/pomwright-v2-migration/references/locator-registration.md +0 -344
- package/srcV2/fixture/base.fixtures.ts +0 -23
- package/srcV2/helpers/navigation.ts +0 -153
- package/srcV2/helpers/playwrightReportLogger.ts +0 -196
- package/srcV2/helpers/sessionStorage.ts +0 -251
- package/srcV2/helpers/stepDecorator.ts +0 -106
- package/srcV2/locators/index.ts +0 -15
- package/srcV2/locators/locatorQueryBuilder.ts +0 -427
- package/srcV2/locators/locatorRegistrationBuilder.ts +0 -558
- package/srcV2/locators/locatorRegistry.ts +0 -541
- package/srcV2/locators/locatorUpdateBuilder.ts +0 -602
- package/srcV2/locators/reusableLocatorBuilder.ts +0 -200
- package/srcV2/locators/types.ts +0 -256
- package/srcV2/locators/utils.ts +0 -309
- package/srcV2/locators/v1SchemaTranslator.ts +0 -178
- package/srcV2/pageObject.ts +0 -105
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
|
|
3
|
-
test("Should validate navigation using RegExp-based urlPath and fullUrl", async ({ testPath, color }) => {
|
|
4
|
-
await testPath.page.goto(testPath.fullUrl);
|
|
5
|
-
|
|
6
|
-
await testPath.expectThisPage();
|
|
7
|
-
|
|
8
|
-
const linkToColorPage = testPath.getNestedLocator("body.link@color");
|
|
9
|
-
await linkToColorPage.waitFor({ state: "visible" });
|
|
10
|
-
|
|
11
|
-
await linkToColorPage.click();
|
|
12
|
-
|
|
13
|
-
await color.expectThisPage();
|
|
14
|
-
await color.validateColorPage();
|
|
15
|
-
});
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
|
|
3
|
-
const toggleStates = {
|
|
4
|
-
on: "On",
|
|
5
|
-
off: "Off",
|
|
6
|
-
} as const;
|
|
7
|
-
|
|
8
|
-
test.describe("iframe handling", () => {
|
|
9
|
-
test.beforeEach(async ({ iframePage }) => {
|
|
10
|
-
await iframePage.page.goto(iframePage.fullUrl);
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("getLocator finds iframeA and iframeB", async ({ iframePage }) => {
|
|
14
|
-
const iframeA = iframePage.getLocator("sectionA.frame");
|
|
15
|
-
const iframeB = iframePage.getLocator("sectionB.frame");
|
|
16
|
-
|
|
17
|
-
await expect(iframeA).toBeVisible();
|
|
18
|
-
await expect(iframeB).toBeVisible();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test("getLocator does not finds iframeC as it is inside iframeB", async ({ iframePage }) => {
|
|
22
|
-
const iframeC = iframePage.getLocator("sectionB.frame.innerFrame");
|
|
23
|
-
|
|
24
|
-
await expect(iframeC).not.toBeVisible();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("getNestedLocator finds iframeA and iframeB", async ({ iframePage }) => {
|
|
28
|
-
const iframeA = iframePage.getNestedLocator("sectionA.frame");
|
|
29
|
-
const iframeB = iframePage.getNestedLocator("sectionB.frame");
|
|
30
|
-
|
|
31
|
-
await expect(iframeA).toBeVisible();
|
|
32
|
-
await expect(iframeB).toBeVisible();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test("getNestedLocator finds nested iframeC", async ({ iframePage }) => {
|
|
36
|
-
const iframeC = iframePage.getNestedLocator("sectionB.frame.innerFrame");
|
|
37
|
-
await expect(iframeC).toBeVisible();
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
test("toggle elements inside each iframe", async ({ iframePage }) => {
|
|
41
|
-
const toggleA = iframePage.getNestedLocator("sectionA.frame.toggle");
|
|
42
|
-
const toggleB = iframePage.getNestedLocator("sectionB.frame.toggle");
|
|
43
|
-
const toggleC = iframePage.getNestedLocator("sectionB.frame.innerFrame.toggle");
|
|
44
|
-
|
|
45
|
-
await expect(toggleA).toHaveText(`Toggle A: ${toggleStates.off}`);
|
|
46
|
-
await expect(toggleB).toHaveText(`Toggle B: ${toggleStates.off}`);
|
|
47
|
-
await expect(toggleC).toHaveText(`Toggle C: ${toggleStates.off}`);
|
|
48
|
-
|
|
49
|
-
await toggleA.click();
|
|
50
|
-
await toggleB.click();
|
|
51
|
-
await toggleC.click();
|
|
52
|
-
|
|
53
|
-
await expect(toggleA).toHaveText(`Toggle A: ${toggleStates.on}`);
|
|
54
|
-
await expect(toggleB).toHaveText(`Toggle B: ${toggleStates.on}`);
|
|
55
|
-
await expect(toggleC).toHaveText(`Toggle C: ${toggleStates.on}`);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
|
|
3
|
-
test("locator definitions with options should resolve playground interactions", async ({ testFilters }) => {
|
|
4
|
-
await testFilters.page.goto(testFilters.fullUrl);
|
|
5
|
-
|
|
6
|
-
const playgroundSection = testFilters.getNestedLocator("body.section@playground");
|
|
7
|
-
|
|
8
|
-
const playgroundBtnRed = testFilters.getNestedLocator("body.section@playground.button@red");
|
|
9
|
-
await playgroundBtnRed.click();
|
|
10
|
-
|
|
11
|
-
await expect(playgroundSection).toHaveCSS("background-color", "rgb(255, 0, 0)");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("getLocatorSchema propagates registered filters and indices to getLocator", async ({ testFilters }) => {
|
|
15
|
-
await testFilters.page.goto(testFilters.fullUrl);
|
|
16
|
-
|
|
17
|
-
const locator = testFilters
|
|
18
|
-
.getLocatorSchema("body.section@playground.button@reset")
|
|
19
|
-
.filter("body.section@playground.button@reset", { hasText: /Reset/i })
|
|
20
|
-
.nth("body.section@playground.button@reset", "first")
|
|
21
|
-
.getLocator();
|
|
22
|
-
|
|
23
|
-
expect(`${locator}`).toEqual("getByRole('button', { name: 'Reset Color' }).filter({ hasText: /Reset/i }).first()");
|
|
24
|
-
});
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
import { SessionStorage } from "pomwright";
|
|
3
|
-
|
|
4
|
-
test("navigation.gotoThisPage runs post-navigation actions", async ({ testPage }) => {
|
|
5
|
-
expect(testPage.navigationActionCount.value).toBe(0);
|
|
6
|
-
|
|
7
|
-
await testPage.navigation.gotoThisPage();
|
|
8
|
-
|
|
9
|
-
expect(testPage.navigationActionCount.value).toBe(1);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test("topMenu should expose notification badge count", async ({ testPage }) => {
|
|
13
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
14
|
-
|
|
15
|
-
const notificationBadge = testPage.getNestedLocator("topMenu.notifications.button.countBadge");
|
|
16
|
-
await expect(notificationBadge).toHaveText("3");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test("stepWithAdvancedReturnType should return the expected payload", async ({ testPage }) => {
|
|
20
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
21
|
-
|
|
22
|
-
const result = await testPage.stepWithAdvancedReturnType();
|
|
23
|
-
|
|
24
|
-
expect(result.status).toBe("ready");
|
|
25
|
-
expect(result.payload[0]?.values[0]?.key).toBe("alpha");
|
|
26
|
-
expect(result.metadata.flags.has("beta")).toBe(true);
|
|
27
|
-
expect(result.metadata.versions.get("v2")?.hash).toBe("def456");
|
|
28
|
-
expect(result.startedAt.getTime()).toBe(0);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test.describe("getLocator helpers on web app", () => {
|
|
32
|
-
test.afterEach(async ({ testPage }) => {
|
|
33
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("getLocator should return the single locator the complete LocatorSchemaPath resolves to", async ({
|
|
37
|
-
testPage,
|
|
38
|
-
}) => {
|
|
39
|
-
const locator = testPage.getLocator("topMenu.notifications.dropdown.item");
|
|
40
|
-
expect(locator).not.toBeNull();
|
|
41
|
-
expect(locator).not.toBeUndefined();
|
|
42
|
-
expect(`${locator}`).toEqual("locator('.w3-bar-item')");
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("should be able to manually chain locators returned by getLocator", async ({ testPage }) => {
|
|
46
|
-
const topMenu = testPage.getLocator("topMenu");
|
|
47
|
-
|
|
48
|
-
const topMenuNotifications = topMenu.locator(testPage.getLocator("topMenu.notifications"));
|
|
49
|
-
|
|
50
|
-
const topMenuNotificationsDropdown = topMenuNotifications.locator(
|
|
51
|
-
testPage.getLocator("topMenu.notifications.dropdown"),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const topMenuNotificationsDropdownItem = topMenuNotificationsDropdown.locator(
|
|
55
|
-
testPage.getLocator("topMenu.notifications.dropdown.item"),
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(topMenuNotificationsDropdownItem).not.toBeNull();
|
|
59
|
-
expect(topMenuNotificationsDropdownItem).not.toBeUndefined();
|
|
60
|
-
expect(`${topMenuNotificationsDropdownItem}`).toEqual(
|
|
61
|
-
"locator('.w3-top').locator(locator('.w3-dropdown-hover')).locator(locator('.w3-dropdown-content')).locator(locator('.w3-bar-item'))",
|
|
62
|
-
);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test("getNestedLocator should support index overrides", async ({ testPage }) => {
|
|
67
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
68
|
-
|
|
69
|
-
const secondNotification = testPage
|
|
70
|
-
.getLocatorSchema("topMenu.notifications.dropdown.item")
|
|
71
|
-
.nth("topMenu.notifications.dropdown.item", 1)
|
|
72
|
-
.getNestedLocator();
|
|
73
|
-
await expect(secondNotification).toHaveText("John Doe posted on your wall");
|
|
74
|
-
|
|
75
|
-
const lastNotification = testPage
|
|
76
|
-
.getLocatorSchema("topMenu.notifications.dropdown.item")
|
|
77
|
-
.nth("topMenu.notifications.dropdown.item", "last")
|
|
78
|
-
.getNestedLocator();
|
|
79
|
-
await expect(lastNotification).toHaveText("Jane likes your post");
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test("setOnNextNavigation waits for a main-frame navigation", async ({ testPage }) => {
|
|
83
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
84
|
-
await testPage.sessionStorage.clear();
|
|
85
|
-
|
|
86
|
-
await testPage.sessionStorage.setOnNextNavigation({ token: "abc" });
|
|
87
|
-
await expect(testPage.sessionStorage.get(["token"])).resolves.toEqual({});
|
|
88
|
-
|
|
89
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
90
|
-
await expect(testPage.sessionStorage.get(["token"])).resolves.toEqual({ token: "abc" });
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("setOnNextNavigation merges multiple calls before navigation", async ({ testPage }) => {
|
|
94
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
95
|
-
await testPage.sessionStorage.clear();
|
|
96
|
-
|
|
97
|
-
await testPage.sessionStorage.setOnNextNavigation({ token: "abc" });
|
|
98
|
-
await testPage.sessionStorage.setOnNextNavigation({ theme: "dark" });
|
|
99
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
100
|
-
|
|
101
|
-
await expect(testPage.sessionStorage.get(["token", "theme"])).resolves.toEqual({
|
|
102
|
-
token: "abc",
|
|
103
|
-
theme: "dark",
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test("clear can target specific keys", async ({ testPage }) => {
|
|
108
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
109
|
-
await testPage.sessionStorage.set({ token: "abc", theme: "dark" });
|
|
110
|
-
|
|
111
|
-
await testPage.sessionStorage.clear("token");
|
|
112
|
-
await expect(testPage.sessionStorage.get(["token", "theme"])).resolves.toEqual({ theme: "dark" });
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
test("sessionStorage set/get supports waitForContext", async ({ testPage }) => {
|
|
116
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
117
|
-
|
|
118
|
-
await testPage.sessionStorage.set({ token: "abc" }, { waitForContext: true });
|
|
119
|
-
|
|
120
|
-
const { token } = await testPage.sessionStorage.get(["token"], { waitForContext: true });
|
|
121
|
-
expect(token).toBe("abc");
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
test("sessionStorage clear supports keys and waitForContext", async ({ testPage }) => {
|
|
125
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
126
|
-
|
|
127
|
-
await testPage.sessionStorage.set({ token: "abc", theme: "dark" }, { waitForContext: true });
|
|
128
|
-
await testPage.sessionStorage.clear("token", { waitForContext: true });
|
|
129
|
-
|
|
130
|
-
const data = await testPage.sessionStorage.get(["token", "theme"], { waitForContext: true });
|
|
131
|
-
expect(data.token).toBeUndefined();
|
|
132
|
-
expect(data.theme).toBe("dark");
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
test("sessionStorage set/get should write immediately on a loaded page", async ({ testPage }) => {
|
|
136
|
-
await testPage.page.goto(testPage.fullUrl);
|
|
137
|
-
|
|
138
|
-
await testPage.sessionStorage.set({ token: { value: "abc" } });
|
|
139
|
-
|
|
140
|
-
const data = await testPage.sessionStorage.get(["token"]);
|
|
141
|
-
expect(data.token).toEqual({ value: "abc" });
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test("sessionStorage set with waitForContext should wait for navigation context", async ({ testPage }) => {
|
|
145
|
-
const freshPage = await testPage.page.context().newPage();
|
|
146
|
-
const sessionStorage = new SessionStorage(freshPage, { label: "SessionStorageTest" });
|
|
147
|
-
|
|
148
|
-
const navigation = freshPage.goto(testPage.fullUrl);
|
|
149
|
-
await sessionStorage.set({ token: { value: "waited" } }, { waitForContext: true });
|
|
150
|
-
await navigation;
|
|
151
|
-
|
|
152
|
-
const data = await sessionStorage.get(["token"]);
|
|
153
|
-
expect(data.token).toEqual({ value: "waited" });
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test("sessionStorage operations reject without waitForContext when no context", async ({ testPage }) => {
|
|
157
|
-
const freshPage = await testPage.page.context().newPage();
|
|
158
|
-
const sessionStorage = new SessionStorage(freshPage, { label: "SessionStorageTest" });
|
|
159
|
-
|
|
160
|
-
await expect(sessionStorage.get(["token"])).rejects.toThrow("SessionStorage context is not available.");
|
|
161
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@fixtures-v2/testApp.fixtures";
|
|
2
|
-
|
|
3
|
-
test("navigation.goto prefixes baseUrl for URL paths", async ({ testPath }) => {
|
|
4
|
-
await testPath.navigation.goto("/testpath");
|
|
5
|
-
await testPath.navigation.expectThisPage();
|
|
6
|
-
|
|
7
|
-
expect(testPath.page.url()).toBe(testPath.fullUrl);
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test("navigation.expectThisPage supports RegExp fullUrl", async ({ testPath, color }) => {
|
|
11
|
-
await testPath.navigation.gotoThisPage();
|
|
12
|
-
|
|
13
|
-
const linkToColorPage = testPath.getNestedLocator("body.link@color");
|
|
14
|
-
await linkToColorPage.waitFor({ state: "visible" });
|
|
15
|
-
await linkToColorPage.click();
|
|
16
|
-
|
|
17
|
-
await color.navigation.expectThisPage();
|
|
18
|
-
});
|
package/pack-build.sh
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
set -e
|
|
4
|
-
|
|
5
|
-
VERSION=$(node -pe "require('./package.json').version")
|
|
6
|
-
|
|
7
|
-
pnpm i --frozen-lockfile || { echo "Installation failed"; exit 1; }
|
|
8
|
-
pnpm build || { echo "Build failed"; exit 1; }
|
|
9
|
-
pnpm pack || { echo "Packaging failed"; exit 1; }
|
|
10
|
-
|
|
11
|
-
echo "Built pomwright-$VERSION.tgz"
|
package/pack-test-v2.sh
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
TEST_DIR="intTestV2"
|
|
4
|
-
|
|
5
|
-
cleanup() {
|
|
6
|
-
if [[ $(basename "$PWD") != "$TEST_DIR" ]]; then
|
|
7
|
-
echo "Not in ./$TEST_DIR directory. Trying to change to ./$TEST_DIR directory..."
|
|
8
|
-
if [[ -d "$TEST_DIR" ]]; then
|
|
9
|
-
cd $TEST_DIR || { echo "Failed to change to ./$TEST_DIR directory"; return 1; }
|
|
10
|
-
else
|
|
11
|
-
echo "The ./$TEST_DIR directory does not exist. Exiting cleanup."
|
|
12
|
-
return 1
|
|
13
|
-
fi
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
# echo "Reverting to latest published version of POMWright in the ./$TEST_DIR directory..."
|
|
17
|
-
# pnpm i -D pomwright@latest || { echo "Failed to revert to latest POMWright version"; exit 1; }
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
trap cleanup EXIT
|
|
21
|
-
|
|
22
|
-
set -e
|
|
23
|
-
|
|
24
|
-
VERSION=$(node -pe "require('./package.json').version")
|
|
25
|
-
|
|
26
|
-
./pack-build.sh
|
|
27
|
-
|
|
28
|
-
cd $TEST_DIR || { echo "Changing directory failed"; exit 1; }
|
|
29
|
-
|
|
30
|
-
pnpm i -D "../pomwright-$VERSION.tgz" || { echo "Local package installation failed"; exit 1; }
|
|
31
|
-
|
|
32
|
-
pnpm i --frozen-lockfile || { echo "Installation failed"; exit 1; }
|
|
33
|
-
pnpm playwright install --with-deps || { echo "Playwright dependencies installation failed"; exit 1; }
|
|
34
|
-
pnpm playwright test --project=chromium || { echo "Tests failed"; exit 1; }
|
|
35
|
-
|
|
36
|
-
echo "Testing completed successfully."
|
package/playwright.base.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
// playwright.base.ts
|
|
2
|
-
import type { PlaywrightTestConfig } from "@playwright/test";
|
|
3
|
-
|
|
4
|
-
// this is only a *type* import → erased at runtime → does NOT trigger the double-load
|
|
5
|
-
// everything below is plain data the subprojects can spread in
|
|
6
|
-
|
|
7
|
-
export const baseConfig: PlaywrightTestConfig = {
|
|
8
|
-
// things you currently have in both configs:
|
|
9
|
-
globalTimeout: 60_000 * 5,
|
|
10
|
-
timeout: 60_000,
|
|
11
|
-
expect: {
|
|
12
|
-
timeout: 5_000,
|
|
13
|
-
},
|
|
14
|
-
fullyParallel: true,
|
|
15
|
-
forbidOnly: !!process.env.CI,
|
|
16
|
-
retries: process.env.CI ? 1 : 1,
|
|
17
|
-
workers: "50%",
|
|
18
|
-
reporter: process.env.CI
|
|
19
|
-
? [
|
|
20
|
-
["html", { open: "never" }],
|
|
21
|
-
["github", { printSteps: false }],
|
|
22
|
-
]
|
|
23
|
-
: [
|
|
24
|
-
["html", { open: "on-failure" }],
|
|
25
|
-
["list", { printSteps: false }],
|
|
26
|
-
],
|
|
27
|
-
use: {
|
|
28
|
-
actionTimeout: 5_000,
|
|
29
|
-
navigationTimeout: 10_000,
|
|
30
|
-
headless: true,
|
|
31
|
-
viewport: { width: 1280, height: 720 },
|
|
32
|
-
ignoreHTTPSErrors: false,
|
|
33
|
-
video: "retry-with-video",
|
|
34
|
-
screenshot: {
|
|
35
|
-
mode: "only-on-failure",
|
|
36
|
-
fullPage: true,
|
|
37
|
-
omitBackground: false,
|
|
38
|
-
},
|
|
39
|
-
trace: "on-all-retries",
|
|
40
|
-
testIdAttribute: "data-testid",
|
|
41
|
-
},
|
|
42
|
-
};
|
package/skills/README.md
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# POMWright Migration Skills
|
|
2
|
-
|
|
3
|
-
AI assistant skills for migrating POMWright page objects between versions.
|
|
4
|
-
|
|
5
|
-
## Available Skills
|
|
6
|
-
|
|
7
|
-
### pomwright-v1-5-bridge-migration
|
|
8
|
-
Migrate v1 `BasePage` page objects to the v1.5 bridge (`BasePageV1toV2`) as an intermediate step toward v2.
|
|
9
|
-
|
|
10
|
-
**Triggered by:**
|
|
11
|
-
- "Migrate/convert/upgrade this page object from v1 to the bridge"
|
|
12
|
-
- "Use BasePageV1toV2 for this page object"
|
|
13
|
-
- Mentioning `BasePageV1toV2` or "bridge" in migration context
|
|
14
|
-
|
|
15
|
-
**Covers:**
|
|
16
|
-
- Changing class inheritance
|
|
17
|
-
- Translating `addSchema`/`initLocatorSchemas` to `defineLocators` with v2 DSL
|
|
18
|
-
- Updating call-site syntax (`getLocator`, `getNestedLocator`, `getLocatorSchema`)
|
|
19
|
-
- Updating filter/index/update/mutation patterns
|
|
20
|
-
|
|
21
|
-
### pomwright-v2-migration
|
|
22
|
-
Migrate page objects to v2 `PageObject` from either v1 `BasePage` or the v1.5 bridge.
|
|
23
|
-
|
|
24
|
-
**Triggered by:**
|
|
25
|
-
- "Migrate/convert/upgrade this page object to v2"
|
|
26
|
-
- "Use v2 PageObject for this page object"
|
|
27
|
-
- Mentioning `PageObject` or "v2" in migration context
|
|
28
|
-
|
|
29
|
-
**Covers:**
|
|
30
|
-
- Class inheritance and constructor signature changes
|
|
31
|
-
- Locator registration with v2 DSL
|
|
32
|
-
- Adding `pageActionsToPerformAfterNavigation`
|
|
33
|
-
- Call-site syntax updates
|
|
34
|
-
- Migrating fixtures, navigation, sessionStorage, and logging
|
|
35
|
-
- Adopting the `@step` decorator
|
|
36
|
-
|
|
37
|
-
## Installation
|
|
38
|
-
|
|
39
|
-
### For Claude Code
|
|
40
|
-
|
|
41
|
-
Copy the skill directories to your local Claude Code skills folder:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
cp -r skills/pomwright-v1-5-bridge-migration ~/.claude/skills/
|
|
45
|
-
cp -r skills/pomwright-v2-migration ~/.claude/skills/
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### For Other AI Assistants
|
|
49
|
-
|
|
50
|
-
These skills are structured as markdown-based instructions with reference documentation. Adapt the content from each `SKILL.md` file according to your AI assistant's skill/prompt format.
|
|
51
|
-
|
|
52
|
-
## Structure
|
|
53
|
-
|
|
54
|
-
Each skill includes:
|
|
55
|
-
- `SKILL.md` - Main skill instructions
|
|
56
|
-
- `references/` - Supporting documentation and examples
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pomwright-v1-5-bridge-migration
|
|
3
|
-
description: >
|
|
4
|
-
Migrate POMWright v1 BasePage page objects to the v1.5 bridge (BasePageV1toV2) as an intermediate
|
|
5
|
-
step toward v2 PageObject. Use when asked to migrate, convert, or upgrade POMWright page objects
|
|
6
|
-
from v1 to the bridge, or when working with BasePageV1toV2. Covers: changing class inheritance,
|
|
7
|
-
translating addSchema/initLocatorSchemas to defineLocators with v2 DSL, updating call-site syntax
|
|
8
|
-
(getLocator, getNestedLocator, getLocatorSchema), and updating filter/index/update/mutation patterns.
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
# POMWright v1.5 Bridge Migration (BasePage -> BasePageV1toV2)
|
|
12
|
-
|
|
13
|
-
Migrate v1 `BasePage` page objects to `BasePageV1toV2` (the bridge), converting locator definitions
|
|
14
|
-
and call-site syntax to v2. The bridge is deprecated and will be removed in 2.0.0; it exists only
|
|
15
|
-
as a staged migration step.
|
|
16
|
-
|
|
17
|
-
## Workflow
|
|
18
|
-
|
|
19
|
-
1. **Inventory** the target POC file: identify `BasePage` extends, `initLocatorSchemas`, all `addSchema` calls, and call-sites using v1 accessors.
|
|
20
|
-
2. **Switch inheritance** from `BasePage` to `BasePageV1toV2`. Constructor signature stays the same (`page, testInfo, baseUrl, urlPath, pocName, pwrl`).
|
|
21
|
-
3. **Add `defineLocators()`** method stub.
|
|
22
|
-
4. **Translate each `addSchema` call** from `initLocatorSchemas` into `this.add(path).method(...)` inside `defineLocators()`. See [references/schema-translation.md](references/schema-translation.md) for the full mapping table and examples.
|
|
23
|
-
5. **Remove translated `addSchema` entries** from `initLocatorSchemas`. Once all are moved, keep `initLocatorSchemas()` as an empty method while still extending `BasePageV1toV2`.
|
|
24
|
-
6. **Update call-site syntax** in tests/helpers/fixtures that consume the POC. See [references/call-site-migration.md](references/call-site-migration.md).
|
|
25
|
-
7. **Verify** by running tests.
|
|
26
|
-
|
|
27
|
-
## Key rules
|
|
28
|
-
|
|
29
|
-
- Paths already registered in `defineLocators` are skipped when the bridge translates `initLocatorSchemas` - no duplicates.
|
|
30
|
-
- v1 schemas using `Locator` instances or missing selector fields cannot be auto-translated; rewrite those in `defineLocators` immediately.
|
|
31
|
-
- `BasePageV1toV2` narrows `this.locators` to `addSchema` only; no other v1 mutations are exposed.
|
|
32
|
-
- v2 accessors (`add`, `getLocator`, `getNestedLocator`, `getLocatorSchema`) are exposed on the bridge and should be used from this point forward.
|
|
33
|
-
- v2 `getLocator`/`getNestedLocator` are **synchronous** (no `await`). v1 versions were async.
|
|
34
|
-
- v2 `getNestedLocator` no longer accepts index maps. Use `getLocatorSchema(path).nth(subPath, index).getNestedLocator()` instead.
|
|
35
|
-
- `filter` replaces v1 `addFilter`. `nth` replaces v1 index maps. Both can be chained in any order.
|
|
36
|
-
|
|
37
|
-
## References
|
|
38
|
-
|
|
39
|
-
- **Schema translation mapping**: [references/schema-translation.md](references/schema-translation.md) - GetByMethod -> v2 DSL mapping table, filter/options translation, reusable locators, frameLocator changes
|
|
40
|
-
- **Call-site migration**: [references/call-site-migration.md](references/call-site-migration.md) - getLocator, getNestedLocator, getLocatorSchema, update, addFilter, index maps, SessionStorage changes
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
# Call-Site Migration: v1 -> v2 accessor syntax
|
|
2
|
-
|
|
3
|
-
## getLocator / getNestedLocator (async -> sync)
|
|
4
|
-
|
|
5
|
-
v1 returns `Promise<Locator>`. v2 returns `Locator` synchronously. Remove `await`.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
// v1
|
|
9
|
-
const btn = await poc.getLocator("navbar.button@login");
|
|
10
|
-
await btn.click();
|
|
11
|
-
|
|
12
|
-
const nested = await poc.getNestedLocator("navbar.button@logout");
|
|
13
|
-
await nested.click();
|
|
14
|
-
|
|
15
|
-
// v2
|
|
16
|
-
await poc.getLocator("navbar.button@login").click();
|
|
17
|
-
await poc.getNestedLocator("navbar.button@logout").click();
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## getNestedLocator with index maps -> getLocatorSchema + nth
|
|
21
|
-
|
|
22
|
-
v1 accepted an optional index map object as second argument. v2 does not; use `getLocatorSchema` with `.nth()` instead.
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
// v1
|
|
26
|
-
const submit = await poc.getNestedLocator("main.form.button@submit", {
|
|
27
|
-
"main.form": 0,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// v2
|
|
31
|
-
const submit = poc
|
|
32
|
-
.getLocatorSchema("main.form.button@submit")
|
|
33
|
-
.nth("main.form", 0)
|
|
34
|
-
.getNestedLocator();
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Multiple indices:
|
|
38
|
-
|
|
39
|
-
```ts
|
|
40
|
-
// v1
|
|
41
|
-
const item = await poc.getNestedLocator("main.list.item.detail", {
|
|
42
|
-
"main.list": 0,
|
|
43
|
-
"main.list.item": 2,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
// v2
|
|
47
|
-
const item = poc
|
|
48
|
-
.getLocatorSchema("main.list.item.detail")
|
|
49
|
-
.nth("main.list", 0)
|
|
50
|
-
.nth("main.list.item", 2)
|
|
51
|
-
.getNestedLocator();
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## addFilter -> filter
|
|
55
|
-
|
|
56
|
-
v1 `addFilter` on `getLocatorSchema()` becomes v2 `filter`. Method name and argument shape changed.
|
|
57
|
-
|
|
58
|
-
```ts
|
|
59
|
-
// v1
|
|
60
|
-
const filtered = await poc
|
|
61
|
-
.getLocatorSchema("main.list.item")
|
|
62
|
-
.addFilter("main.list", { hasText: "list" })
|
|
63
|
-
.addFilter("main.list.item", { hasText: "Row" })
|
|
64
|
-
.getNestedLocator({ "main.list": 0, "main.list.item": -1 });
|
|
65
|
-
|
|
66
|
-
// v2
|
|
67
|
-
const filtered = poc
|
|
68
|
-
.getLocatorSchema("main.list.item")
|
|
69
|
-
.filter("main.list", { hasText: "list" })
|
|
70
|
-
.nth("main.list", 0)
|
|
71
|
-
.filter({ hasText: "Row" }) // omitted subPath defaults to terminal path
|
|
72
|
-
.nth(-1) // omitted subPath defaults to terminal path
|
|
73
|
-
.getNestedLocator();
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
Key difference: v2 `filter` and `nth` can be interleaved in any order. v1 required all filters first, then one index map at the end.
|
|
77
|
-
|
|
78
|
-
## update (schema mutation)
|
|
79
|
-
|
|
80
|
-
v1 `update` accepted a partial schema object. v2 `update` returns a sub-builder where you chain the locator method with override options.
|
|
81
|
-
|
|
82
|
-
```ts
|
|
83
|
-
// v1
|
|
84
|
-
const patched = await poc
|
|
85
|
-
.getLocatorSchema("main.button@login")
|
|
86
|
-
.update("main.button@login", { roleOptions: { name: "Sign in" } })
|
|
87
|
-
.getNestedLocator();
|
|
88
|
-
|
|
89
|
-
// v2
|
|
90
|
-
const patched = poc
|
|
91
|
-
.getLocatorSchema("main.button@login")
|
|
92
|
-
.update() // defaults to terminal path
|
|
93
|
-
.getByRole({ name: "Sign in" }) // PATCH-style: only override options
|
|
94
|
-
.getNestedLocator();
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
v2 also adds `replace` (full replacement) and `remove` (drop a subpath from chain):
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
// replace the entire locator strategy for a subpath
|
|
101
|
-
const replaced = poc
|
|
102
|
-
.getLocatorSchema("main.button@login")
|
|
103
|
-
.replace()
|
|
104
|
-
.getByText("Sign in")
|
|
105
|
-
.getNestedLocator();
|
|
106
|
-
|
|
107
|
-
// remove a segment from the chain
|
|
108
|
-
const removed = poc
|
|
109
|
-
.getLocatorSchema("main.button@login")
|
|
110
|
-
.remove("main")
|
|
111
|
-
.getNestedLocator();
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## getLocatorSchema().getLocator() / .getNestedLocator()
|
|
115
|
-
|
|
116
|
-
v1 terminal resolution was async. v2 is sync.
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
// v1
|
|
120
|
-
const loc = await poc.getLocatorSchema("main.button@login").getLocator();
|
|
121
|
-
const nested = await poc.getLocatorSchema("main.button@login").getNestedLocator();
|
|
122
|
-
|
|
123
|
-
// v2
|
|
124
|
-
const loc = poc.getLocatorSchema("main.button@login").getLocator();
|
|
125
|
-
const nested = poc.getLocatorSchema("main.button@login").getNestedLocator();
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## describe (v2 only, no v1 equivalent)
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
const btn = poc
|
|
132
|
-
.getLocatorSchema("main.region@security.button@edit")
|
|
133
|
-
.filter({ hasText: "Change password" })
|
|
134
|
-
.describe("Change password")
|
|
135
|
-
.getNestedLocator();
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
## SessionStorage signature changes
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
// v1
|
|
142
|
-
await poc.sessionStorage.set({ token: "abc" }, true); // boolean reload
|
|
143
|
-
await poc.sessionStorage.get(["token"]);
|
|
144
|
-
await poc.sessionStorage.clear();
|
|
145
|
-
|
|
146
|
-
// v2
|
|
147
|
-
await poc.sessionStorage.set({ token: "abc" }, { reload: true });
|
|
148
|
-
await poc.sessionStorage.get(["token"], { waitForContext: true });
|
|
149
|
-
await poc.sessionStorage.clear(); // clears all
|
|
150
|
-
await poc.sessionStorage.clear(["token"]); // clears specific keys
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Import changes
|
|
154
|
-
|
|
155
|
-
```ts
|
|
156
|
-
// v1
|
|
157
|
-
import { BasePage, GetByMethod } from "pomwright";
|
|
158
|
-
|
|
159
|
-
// v1.5 bridge
|
|
160
|
-
import { BasePageV1toV2, GetByMethod } from "pomwright";
|
|
161
|
-
|
|
162
|
-
// When all schemas moved to defineLocators, remove GetByMethod import.
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## filter has/hasNot value changes
|
|
166
|
-
|
|
167
|
-
v1 `filter.has`/`filter.hasNot` accepted `Locator` instances. v2 accepts **registry path strings** or `Locator` instances from `getLocator`/`getNestedLocator`.
|
|
168
|
-
|
|
169
|
-
```ts
|
|
170
|
-
// v1 (Locator instance in filter)
|
|
171
|
-
.addFilter("main.card", { has: someLocator })
|
|
172
|
-
|
|
173
|
-
// v2 (path string reference)
|
|
174
|
-
.filter("main.card", { has: "main.card.badge" })
|
|
175
|
-
|
|
176
|
-
// v2 (Locator instance from registry)
|
|
177
|
-
.filter("main.card", { has: poc.getNestedLocator("main.card.badge") })
|
|
178
|
-
```
|