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,114 +0,0 @@
1
- import type { LocatorRegistry } from "pomwright";
2
-
3
- export type Paths =
4
- | "one"
5
- | "one.two"
6
- | "body"
7
- | "body.section"
8
- | "body.section.heading"
9
- | "body.section.button"
10
- | "body.section@playground"
11
- | "body.section@playground.heading"
12
- | "body.section@playground.button"
13
- | "body.section@playground.button@red"
14
- | "body.section@playground.button@reset"
15
- /**
16
- * Fictional LocatorSchema do not exist in the DOM of the /testfilters page:
17
- */
18
- | "fictional.filter@undefined"
19
- | "fictional.filter@optionsUndefined"
20
- | "fictional.locatorWithfilter@allOptions"
21
- | "fictional.locatorAndOptionsWithfilter@allOptions"
22
- | "fictional.filter@has"
23
- | "fictional.filter@hasNot"
24
- | "fictional.filter@hasText"
25
- | "fictional.filter@hasNotText"
26
- | "fictional.filter@hasNotText.filter@hasText"
27
- | "fictional.filter@hasNotText.filter@hasText.filter@hasNotText"
28
- | "fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText";
29
-
30
- export function defineLocators(registry: LocatorRegistry<Paths>) {
31
- registry.add("one").locator("div.one");
32
-
33
- registry.add("one.two").locator("div.two").filter({ hasText: "two" }).nth(0);
34
-
35
- registry.add("body").locator("body");
36
-
37
- registry.add("body.section").locator("section");
38
-
39
- registry.add("body.section.heading").getByRole("heading", { level: 2 });
40
-
41
- registry.add("body.section.button").getByRole("button");
42
-
43
- registry.add("body.section@playground").locator("section", { hasText: /Playground/i });
44
-
45
- registry
46
- .add("body.section@playground.heading")
47
- .getByRole("heading", { name: "Primary Colors Playground", level: 2, exact: true });
48
-
49
- registry.add("body.section@playground.button").getByRole("button");
50
-
51
- registry.add("body.section@playground.button@red").getByRole("button", { name: "Red" });
52
-
53
- registry.add("body.section@playground.button@reset").getByRole("button", { name: "Reset Color" });
54
-
55
- /** --------------------------- Fictional LocatorSchema ---------------------------
56
- * The following LocatorSchema DO NOT exist in the DOM of the /testfilters page
57
- *
58
- * They are used for testing that the getNestedLocator/getLocator methods correctly
59
- * produces correct locator selector strings for LocatorSchema with/without filter.
60
- */
61
-
62
- registry.add("fictional.filter@undefined").getByRole("button");
63
-
64
- registry
65
- .add("fictional.filter@optionsUndefined")
66
- .getByRole("button")
67
- .filter({ has: undefined, hasNot: undefined, hasText: undefined, hasNotText: undefined });
68
-
69
- registry
70
- .add("fictional.locatorWithfilter@allOptions")
71
- .getByRole("button")
72
- .filter({
73
- has: "body.section",
74
- hasNot: "body.section.button",
75
- hasText: "hasText",
76
- hasNotText: "hasNotText",
77
- });
78
-
79
- registry
80
- .add("fictional.locatorAndOptionsWithfilter@allOptions")
81
- .getByRole("button", { name: "roleOptions" })
82
- .filter({
83
- has: "body.section.heading",
84
- hasNot: "body.section.button",
85
- hasText: "hasText",
86
- hasNotText: "hasNotText",
87
- });
88
-
89
- registry
90
- .add("fictional.filter@has")
91
- .getByRole("button")
92
- .filter({ has: "body.section.heading" });
93
-
94
- registry
95
- .add("fictional.filter@hasNot")
96
- .getByRole("button")
97
- .filter({ hasNot: "body.section.button" });
98
-
99
- registry.add("fictional.filter@hasText").getByRole("button").filter({ hasText: "hasText" });
100
-
101
- registry.add("fictional.filter@hasNotText").getByRole("button").filter({ hasNotText: "hasNotText" });
102
-
103
- registry.add("fictional.filter@hasNotText.filter@hasText").getByRole("button").filter({ hasText: "hasText" });
104
-
105
- registry
106
- .add("fictional.filter@hasNotText.filter@hasText.filter@hasNotText")
107
- .getByRole("button")
108
- .filter({ hasNotText: "hasNotText" });
109
-
110
- registry
111
- .add("fictional.filter@hasNotText.filter@hasText.filter@hasNotText.filter@hasText")
112
- .getByRole("button")
113
- .filter({ hasText: "hasText" });
114
- }
@@ -1,23 +0,0 @@
1
- import { type Page, test } from "@playwright/test";
2
- import TestApp from "../../testApp.base";
3
- import { defineLocators, type Paths } from "./testfilters.locatorSchema";
4
-
5
- export default class TestFiltersV2 extends TestApp<Paths> {
6
- constructor(page: Page) {
7
- super(page, "/testfilters");
8
- }
9
-
10
- protected defineLocators(): void {
11
- defineLocators(this.locatorRegistry);
12
- }
13
-
14
- protected pageActionsToPerformAfterNavigation(): (() => Promise<void>)[] | null {
15
- return [];
16
- }
17
-
18
- async expectThisPage() {
19
- await test.step(`Expect Page: ${this.urlPath}`, async () => {
20
- await this.page.waitForURL(this.fullUrl);
21
- });
22
- }
23
- }
@@ -1,20 +0,0 @@
1
- import type { Page } from "@playwright/test";
2
- import { type NavigationOptions, PageObject, type UrlPathTypeFromOptions, type UrlTypeOptions } from "pomwright";
3
-
4
- type BaseOptions<Options extends UrlTypeOptions> = {
5
- baseUrlType: string;
6
- urlPathType: UrlPathTypeFromOptions<Options>;
7
- };
8
-
9
- export default abstract class TestApp<
10
- Paths extends string,
11
- Options extends UrlTypeOptions = { baseUrlType: string; urlPathType: string },
12
- > extends PageObject<Paths, BaseOptions<Options>> {
13
- protected constructor(
14
- page: Page,
15
- urlPath: UrlPathTypeFromOptions<BaseOptions<Options>>,
16
- options?: { label?: string; navOptions?: NavigationOptions },
17
- ) {
18
- super(page, "http://localhost:8080", urlPath, options);
19
- }
20
- }
@@ -1,54 +0,0 @@
1
- import { defineConfig, devices } from "@playwright/test";
2
- import dotenv from "dotenv";
3
- import { baseConfig } from "../playwright.base";
4
-
5
- dotenv.config({ override: false, quiet: true });
6
-
7
- export default defineConfig({
8
- ...baseConfig,
9
- testDir: "./tests",
10
-
11
- webServer: process.env.CI
12
- ? [
13
- {
14
- command: "pnpm start",
15
- url: "http://localhost:8080/",
16
- timeout: 5 * 60_000,
17
- reuseExistingServer: false,
18
- ignoreHTTPSErrors: false,
19
- },
20
- ]
21
- : [
22
- {
23
- command: "pnpm start",
24
- url: "http://localhost:8080/",
25
- timeout: 5 * 60_000,
26
- reuseExistingServer: true,
27
- ignoreHTTPSErrors: false,
28
- },
29
- ],
30
-
31
- projects: [
32
- {
33
- name: "chromium",
34
- use: {
35
- ...(baseConfig.use ?? {}),
36
- ...devices["Desktop Chrome"],
37
- },
38
- },
39
- {
40
- name: "firefox",
41
- use: {
42
- ...(baseConfig.use ?? {}),
43
- ...devices["Desktop Firefox"],
44
- },
45
- },
46
- {
47
- name: "webkit",
48
- use: {
49
- ...(baseConfig.use ?? {}),
50
- ...devices["Desktop Safari"],
51
- },
52
- },
53
- ],
54
- });
@@ -1,216 +0,0 @@
1
- const express = require("express");
2
- const path = require("node:path");
3
-
4
- const app = express();
5
- const port = 8080;
6
-
7
- // Serve static files from the "test-data/staticPage" directory
8
- app.use(express.static(path.join(__dirname, "test-data/staticPage")));
9
-
10
- // Route to handle "/testpath/:color"
11
- app.get("/testpath/:color", (req, res) => {
12
- const color = req.params.color;
13
-
14
- // Ensure the color is a valid 3 or 6-character hex code
15
- if (!/^([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(color)) {
16
- res.status(400).send("Invalid color code.");
17
- return;
18
- }
19
-
20
- // Return a simple HTML page with the background set to the color
21
- res.send(`
22
- <html>
23
- <body style="background-color: #${color}; height: 100vh; margin: 0; display: flex; justify-content: center; align-items: center; flex-direction: column;">
24
- <h1 style="border: 3px solid black; padding: 10px; background-color: #E0E0E0; color: black;">Your Random Color is:</h1>
25
- <table role="table" aria-label="Hex Code Information" style="text-align: center; font-size: 24px; background-color: #E0E0E0; color: black; border-collapse: collapse;">
26
- <tr role="row">
27
- <td role="rowheader" aria-label="Hex Code Header" style="border: 3px solid black; padding: 10px; background-color: silver;">Hex Code:</td>
28
- </tr>
29
- <tr role="row">
30
- <td role="cell" aria-label="color code" style="border: 3px solid black; padding: 10px;">#${color}</td>
31
- </tr>
32
- </table>
33
- </body>
34
- </html>
35
- `);
36
- });
37
-
38
- // Route to handle "/testpath" with a link that generates a new random color on click
39
- app.get("/testpath", (req, res) => {
40
- res.send(`
41
- <html>
42
- <body style="display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0;">
43
- <a id="randomColorLink" href="#" style="font-size: 24px;" aria-label="Random Color Link">Go to Random Color Page</a>
44
-
45
- <script>
46
- // Function to generate a random hex color of either 3 or 6 digits
47
- function generateRandomColor() {
48
- // Randomly choose between generating a 3-character or 6-character hex color
49
- const isShort = Math.random() < 0.5;
50
- let randomColor = Math.floor(Math.random() * (isShort ? 4095 : 16777215)).toString(16);
51
- // Pad the color if necessary to make it 3 or 6 characters long
52
- return isShort ? randomColor.padStart(3, '0') : randomColor.padStart(6, '0');
53
- }
54
-
55
- // Add a click event listener to the link
56
- document.getElementById('randomColorLink').addEventListener('click', function(event) {
57
- event.preventDefault(); // Prevent the default action of the link
58
- const randomColor = generateRandomColor(); // Generate a new random color
59
- window.location.href = '/testpath/' + randomColor; // Navigate to the random color URL
60
- });
61
- </script>
62
- </body>
63
- </html>
64
- `);
65
- });
66
-
67
- // Route to handle "/testfilters"
68
- app.get("/testfilters", (req, res) => {
69
- res.send(`
70
- <html>
71
- <body style="margin: 0; padding: 20px; font-family: Arial, sans-serif;">
72
- <section id="section1" style="margin-bottom: 20px; border: 1px solid black; padding: 10px;">
73
- <h2 style="color: silver; text-shadow: 1px 1px 1px black;">Primary Colors Section</h2>
74
- <button style="background-color: red; color: white; padding: 10px;" onclick="changeColor('section1', 'red')">Red</button>
75
- <button style="background-color: blue; color: white; padding: 10px;" onclick="changeColor('section1', 'blue')">Blue</button>
76
- <button style="background-color: green; color: white; padding: 10px;" onclick="changeColor('section1', 'green')">Green</button>
77
- <button style="background-color: lightgray; color: black; padding: 10px;" onclick="resetColor('section1')">Reset Color</button>
78
- </section>
79
-
80
- <section id="section2" style="margin-bottom: 20px; border: 1px solid black; padding: 10px;">
81
- <h2 style="color: silver; text-shadow: 1px 1px 1px black;">Primary Colors Explorer</h2>
82
- <button style="background-color: red; color: white; padding: 10px;" onclick="changeColor('section2', 'red')">Red</button>
83
- <button style="background-color: blue; color: white; padding: 10px;" onclick="changeColor('section2', 'blue')">Blue</button>
84
- <button style="background-color: green; color: white; padding: 10px;" onclick="changeColor('section2', 'green')">Green</button>
85
- <button style="background-color: lightgray; color: black; padding: 10px;" onclick="resetColor('section2')">Reset Color</button>
86
- </section>
87
-
88
- <section id="section3" aria-label="Accessible Section" style="margin-bottom: 20px; border: 1px solid black; padding: 10px;">
89
- <h2 style="color: silver; text-shadow: 1px 1px 1px black;">Primary Colors Test</h2>
90
- <button style="background-color: red; color: white; padding: 10px;" onclick="changeColor('section3', 'red')">Red</button>
91
- <button style="background-color: blue; color: white; padding: 10px;" onclick="changeColor('section3', 'blue')">Blue</button>
92
- <button style="background-color: green; color: white; padding: 10px;" onclick="changeColor('section3', 'green')">Green</button>
93
- <button style="background-color: lightgray; color: black; padding: 10px;" onclick="resetColor('section3')">Reset Color</button>
94
- </section>
95
-
96
- <section id="section4" style="margin-bottom: 20px; border: 1px solid black; padding: 10px;">
97
- <h2 style="color: silver; text-shadow: 1px 1px 1px black;">Primary Colors Playground</h2>
98
- <button style="background-color: red; color: white; padding: 10px;" onclick="changeColor('section4', 'red')">Red</button>
99
- <button style="background-color: blue; color: white; padding: 10px;" onclick="changeColor('section4', 'blue')">Blue</button>
100
- <button style="background-color: green; color: white; padding: 10px;" onclick="changeColor('section4', 'green')">Green</button>
101
- <button style="background-color: lightgray; color: black; padding: 10px;" onclick="resetColor('section4')">Reset Color</button>
102
- </section>
103
-
104
- <script>
105
- function changeColor(sectionId, color) {
106
- document.getElementById(sectionId).style.backgroundColor = color;
107
- }
108
-
109
- function resetColor(sectionId) {
110
- document.getElementById(sectionId).style.backgroundColor = "";
111
- }
112
- </script>
113
- </body>
114
- </html>
115
- `);
116
- });
117
-
118
- app.get("/iframe", (_req, res) => {
119
- res.send(`
120
- <html>
121
- <body style="margin: 0; padding: 20px; font-family: Arial, sans-serif;">
122
- <h1>Iframe playground</h1>
123
-
124
- <section id="sectionA" style="margin-bottom: 20px; border: 2px solid #333; padding: 10px;">
125
- <h2>Section A</h2>
126
- <iframe
127
- id="iframeA"
128
- title="iframeA"
129
- src="/iframe/a"
130
- style="width: 400px; height: 200px; border: 3px solid #0066cc;"
131
- ></iframe>
132
- </section>
133
-
134
- <section id="sectionB" style="margin-bottom: 20px; border: 2px solid #333; padding: 10px;">
135
- <h2>Section B</h2>
136
- <iframe
137
- id="iframeB"
138
- title="iframeB"
139
- src="/iframe/b"
140
- style="width: 400px; height: 240px; border: 3px solid #cc6600;"
141
- ></iframe>
142
- </section>
143
- </body>
144
- </html>
145
- `);
146
- });
147
-
148
- app.get("/iframe/a", (_req, res) => {
149
- res.send(`
150
- <html>
151
- <body style="margin: 0; padding: 10px; font-family: Arial, sans-serif;">
152
- <h3>Frame A</h3>
153
- <button id="toggleA" data-testid="toggle-a" aria-pressed="false">Toggle A: Off</button>
154
- <script>
155
- const buttonA = document.getElementById('toggleA');
156
- buttonA.addEventListener('click', () => {
157
- const pressed = buttonA.getAttribute('aria-pressed') === 'true';
158
- buttonA.setAttribute('aria-pressed', (!pressed).toString());
159
- buttonA.textContent = pressed ? 'Toggle A: Off' : 'Toggle A: On';
160
- });
161
- </script>
162
- </body>
163
- </html>
164
- `);
165
- });
166
-
167
- app.get("/iframe/b", (_req, res) => {
168
- res.send(`
169
- <html>
170
- <body style="margin: 0; padding: 10px; font-family: Arial, sans-serif;">
171
- <h3>Frame B</h3>
172
- <button id="toggleB" data-testid="toggle-b" aria-pressed="false">Toggle B: Off</button>
173
-
174
- <iframe
175
- id="iframeC"
176
- title="iframeC"
177
- src="/iframe/c"
178
- style="display: block; margin-top: 12px; width: 320px; height: 160px; border: 3px solid #009933;"
179
- ></iframe>
180
-
181
- <script>
182
- const buttonB = document.getElementById('toggleB');
183
- buttonB.addEventListener('click', () => {
184
- const pressed = buttonB.getAttribute('aria-pressed') === 'true';
185
- buttonB.setAttribute('aria-pressed', (!pressed).toString());
186
- buttonB.textContent = pressed ? 'Toggle B: Off' : 'Toggle B: On';
187
- });
188
- </script>
189
- </body>
190
- </html>
191
- `);
192
- });
193
-
194
- app.get("/iframe/c", (_req, res) => {
195
- res.send(`
196
- <html>
197
- <body style="margin: 0; padding: 10px; font-family: Arial, sans-serif;">
198
- <h3>Frame C</h3>
199
- <button id="toggleC" data-testid="toggle-c" aria-pressed="false">Toggle C: Off</button>
200
- <script>
201
- const buttonC = document.getElementById('toggleC');
202
- buttonC.addEventListener('click', () => {
203
- const pressed = buttonC.getAttribute('aria-pressed') === 'true';
204
- buttonC.setAttribute('aria-pressed', (!pressed).toString());
205
- buttonC.textContent = pressed ? 'Toggle C: Off' : 'Toggle C: On';
206
- });
207
- </script>
208
- </body>
209
- </html>
210
- `);
211
- });
212
-
213
- // Start the server
214
- app.listen(port, () => {
215
- console.log(`Server running at http://localhost:${port}/`);
216
- });