@demon-utils/playwright 0.1.0 → 0.1.3

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/dist/index.js ADDED
@@ -0,0 +1,82 @@
1
+ // src/commentary.ts
2
+ var TOOLTIP_ID = "demon-commentary-tooltip";
3
+ async function showCommentary(page, options) {
4
+ await page.evaluate(({ selector, text, tooltipId }) => {
5
+ const target = document.querySelector(selector);
6
+ if (!target) {
7
+ throw new Error(`demon commentary: element not found for selector "${selector}"`);
8
+ }
9
+ document.getElementById(tooltipId)?.remove();
10
+ const rect = target.getBoundingClientRect();
11
+ const tooltip = document.createElement("div");
12
+ tooltip.id = tooltipId;
13
+ tooltip.textContent = text;
14
+ const style = document.createElement("style");
15
+ style.setAttribute("data-demon-commentary", "");
16
+ style.textContent = `
17
+ @keyframes demon-commentary-in {
18
+ from {
19
+ opacity: 0;
20
+ transform: translateY(8px);
21
+ }
22
+ to {
23
+ opacity: 1;
24
+ transform: translateY(0);
25
+ }
26
+ }
27
+ @keyframes demon-commentary-out {
28
+ from {
29
+ opacity: 1;
30
+ transform: translateY(0);
31
+ }
32
+ to {
33
+ opacity: 0;
34
+ transform: translateY(8px);
35
+ }
36
+ }
37
+ #${tooltipId} {
38
+ position: fixed;
39
+ z-index: 2147483647;
40
+ background: #1a1a2e;
41
+ color: #eee;
42
+ padding: 8px 14px;
43
+ border-radius: 6px;
44
+ font: 14px/1.4 system-ui, sans-serif;
45
+ max-width: 320px;
46
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
47
+ pointer-events: none;
48
+ animation: demon-commentary-in 0.3s ease-out forwards;
49
+ }
50
+ #${tooltipId}.demon-commentary-hiding {
51
+ animation: demon-commentary-out 0.25s ease-in forwards;
52
+ }
53
+ `;
54
+ document.querySelector("style[data-demon-commentary]")?.remove();
55
+ document.head.appendChild(style);
56
+ const top = rect.bottom + 10;
57
+ const left = rect.left + rect.width / 2;
58
+ tooltip.style.top = `${top}px`;
59
+ tooltip.style.left = `${left}px`;
60
+ tooltip.style.transform = `translateX(-50%)`;
61
+ document.body.appendChild(tooltip);
62
+ }, { selector: options.selector, text: options.text, tooltipId: TOOLTIP_ID });
63
+ }
64
+ async function hideCommentary(page) {
65
+ await page.evaluate((tooltipId) => {
66
+ const tooltip = document.getElementById(tooltipId);
67
+ if (!tooltip)
68
+ return;
69
+ tooltip.classList.add("demon-commentary-hiding");
70
+ tooltip.addEventListener("animationend", () => {
71
+ tooltip.remove();
72
+ document.querySelector("style[data-demon-commentary]")?.remove();
73
+ }, { once: true });
74
+ }, TOOLTIP_ID);
75
+ await page.waitForTimeout(300);
76
+ }
77
+ export {
78
+ showCommentary,
79
+ hideCommentary
80
+ };
81
+
82
+ //# debugId=308A425302523F0964756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/commentary.ts"],
4
+ "sourcesContent": [
5
+ "import type { Page } from \"@playwright/test\";\n\nexport interface ShowCommentaryOptions {\n selector: string;\n text: string;\n}\n\nconst TOOLTIP_ID = \"demon-commentary-tooltip\";\n\nexport async function showCommentary(\n page: Page,\n options: ShowCommentaryOptions,\n): Promise<void> {\n await page.evaluate(\n ({ selector, text, tooltipId }) => {\n const target = document.querySelector(selector);\n if (!target) {\n throw new Error(\n `demon commentary: element not found for selector \"${selector}\"`,\n );\n }\n\n // Remove any existing tooltip\n document.getElementById(tooltipId)?.remove();\n\n const rect = target.getBoundingClientRect();\n\n const tooltip = document.createElement(\"div\");\n tooltip.id = tooltipId;\n tooltip.textContent = text;\n\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-demon-commentary\", \"\");\n style.textContent = `\n @keyframes demon-commentary-in {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n @keyframes demon-commentary-out {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(8px);\n }\n }\n #${tooltipId} {\n position: fixed;\n z-index: 2147483647;\n background: #1a1a2e;\n color: #eee;\n padding: 8px 14px;\n border-radius: 6px;\n font: 14px/1.4 system-ui, sans-serif;\n max-width: 320px;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n pointer-events: none;\n animation: demon-commentary-in 0.3s ease-out forwards;\n }\n #${tooltipId}.demon-commentary-hiding {\n animation: demon-commentary-out 0.25s ease-in forwards;\n }\n `;\n\n // Remove previous style if any\n document.querySelector(\"style[data-demon-commentary]\")?.remove();\n document.head.appendChild(style);\n\n // Position below the target element, horizontally centered\n const top = rect.bottom + 10;\n const left = rect.left + rect.width / 2;\n tooltip.style.top = `${top}px`;\n tooltip.style.left = `${left}px`;\n tooltip.style.transform = `translateX(-50%)`;\n\n document.body.appendChild(tooltip);\n },\n { selector: options.selector, text: options.text, tooltipId: TOOLTIP_ID },\n );\n}\n\nexport async function hideCommentary(page: Page): Promise<void> {\n await page.evaluate((tooltipId) => {\n const tooltip = document.getElementById(tooltipId);\n if (!tooltip) return;\n\n tooltip.classList.add(\"demon-commentary-hiding\");\n\n tooltip.addEventListener(\n \"animationend\",\n () => {\n tooltip.remove();\n document.querySelector(\"style[data-demon-commentary]\")?.remove();\n },\n { once: true },\n );\n }, TOOLTIP_ID);\n\n // Wait for the animate-out to complete\n await page.waitForTimeout(300);\n}\n"
6
+ ],
7
+ "mappings": ";AAOA,IAAM,aAAa;AAEnB,eAAsB,cAAc,CAClC,MACA,SACe;AAAA,EACf,MAAM,KAAK,SACT,GAAG,UAAU,MAAM,gBAAgB;AAAA,IACjC,MAAM,SAAS,SAAS,cAAc,QAAQ;AAAA,IAC9C,IAAI,CAAC,QAAQ;AAAA,MACX,MAAM,IAAI,MACR,qDAAqD,WACvD;AAAA,IACF;AAAA,IAGA,SAAS,eAAe,SAAS,GAAG,OAAO;AAAA,IAE3C,MAAM,OAAO,OAAO,sBAAsB;AAAA,IAE1C,MAAM,UAAU,SAAS,cAAc,KAAK;AAAA,IAC5C,QAAQ,KAAK;AAAA,IACb,QAAQ,cAAc;AAAA,IAEtB,MAAM,QAAQ,SAAS,cAAc,OAAO;AAAA,IAC5C,MAAM,aAAa,yBAAyB,EAAE;AAAA,IAC9C,MAAM,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAqBf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAaA;AAAA;AAAA;AAAA;AAAA,IAML,SAAS,cAAc,8BAA8B,GAAG,OAAO;AAAA,IAC/D,SAAS,KAAK,YAAY,KAAK;AAAA,IAG/B,MAAM,MAAM,KAAK,SAAS;AAAA,IAC1B,MAAM,OAAO,KAAK,OAAO,KAAK,QAAQ;AAAA,IACtC,QAAQ,MAAM,MAAM,GAAG;AAAA,IACvB,QAAQ,MAAM,OAAO,GAAG;AAAA,IACxB,QAAQ,MAAM,YAAY;AAAA,IAE1B,SAAS,KAAK,YAAY,OAAO;AAAA,KAEnC,EAAE,UAAU,QAAQ,UAAU,MAAM,QAAQ,MAAM,WAAW,WAAW,CAC1E;AAAA;AAGF,eAAsB,cAAc,CAAC,MAA2B;AAAA,EAC9D,MAAM,KAAK,SAAS,CAAC,cAAc;AAAA,IACjC,MAAM,UAAU,SAAS,eAAe,SAAS;AAAA,IACjD,IAAI,CAAC;AAAA,MAAS;AAAA,IAEd,QAAQ,UAAU,IAAI,yBAAyB;AAAA,IAE/C,QAAQ,iBACN,gBACA,MAAM;AAAA,MACJ,QAAQ,OAAO;AAAA,MACf,SAAS,cAAc,8BAA8B,GAAG,OAAO;AAAA,OAEjE,EAAE,MAAM,KAAK,CACf;AAAA,KACC,UAAU;AAAA,EAGb,MAAM,KAAK,eAAe,GAAG;AAAA;",
8
+ "debugId": "308A425302523F0964756E2164756E21",
9
+ "names": []
10
+ }
package/package.json CHANGED
@@ -1,10 +1,25 @@
1
1
  {
2
2
  "name": "@demon-utils/playwright",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
- "module": "src/index.ts",
5
+ "module": "dist/index.js",
6
+ "types": "src/index.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./src/index.ts"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "src"
16
+ ],
6
17
  "type": "module",
18
+ "peerDependencies": {
19
+ "@playwright/test": ">=1.40.0"
20
+ },
7
21
  "devDependencies": {
8
- "@types/bun": "latest"
22
+ "@types/bun": "latest",
23
+ "@playwright/test": "^1.50.0"
9
24
  }
10
25
  }
@@ -0,0 +1,71 @@
1
+ import { test, expect } from "@playwright/test";
2
+
3
+ import { showCommentary, hideCommentary } from "./commentary.ts";
4
+
5
+ const TOOLTIP_ID = "demon-commentary-tooltip";
6
+
7
+ const INLINE_HTML = `data:text/html,
8
+ <html>
9
+ <body>
10
+ <button id="submit-btn" style="margin: 100px;">Submit</button>
11
+ </body>
12
+ </html>`;
13
+
14
+ test("showCommentary injects a tooltip near the target element", async ({
15
+ page,
16
+ }) => {
17
+ await page.goto(INLINE_HTML);
18
+
19
+ await showCommentary(page, {
20
+ selector: "#submit-btn",
21
+ text: "Now we submit the form",
22
+ });
23
+
24
+ const tooltip = page.locator(`#${TOOLTIP_ID}`);
25
+ await expect(tooltip).toBeVisible();
26
+ await expect(tooltip).toHaveText("Now we submit the form");
27
+ });
28
+
29
+ test("hideCommentary removes the tooltip with animation", async ({ page }) => {
30
+ await page.goto(INLINE_HTML);
31
+
32
+ await showCommentary(page, {
33
+ selector: "#submit-btn",
34
+ text: "This will disappear",
35
+ });
36
+
37
+ await expect(page.locator(`#${TOOLTIP_ID}`)).toBeVisible();
38
+
39
+ await hideCommentary(page);
40
+
41
+ await expect(page.locator(`#${TOOLTIP_ID}`)).toHaveCount(0);
42
+ });
43
+
44
+ test("showCommentary replaces an existing tooltip", async ({ page }) => {
45
+ await page.goto(INLINE_HTML);
46
+
47
+ await showCommentary(page, {
48
+ selector: "#submit-btn",
49
+ text: "First message",
50
+ });
51
+
52
+ await showCommentary(page, {
53
+ selector: "#submit-btn",
54
+ text: "Second message",
55
+ });
56
+
57
+ const tooltips = page.locator(`#${TOOLTIP_ID}`);
58
+ await expect(tooltips).toHaveCount(1);
59
+ await expect(tooltips).toHaveText("Second message");
60
+ });
61
+
62
+ test("showCommentary throws for missing selector", async ({ page }) => {
63
+ await page.goto(INLINE_HTML);
64
+
65
+ await expect(
66
+ showCommentary(page, {
67
+ selector: "#nonexistent",
68
+ text: "Should fail",
69
+ }),
70
+ ).rejects.toThrow();
71
+ });
@@ -0,0 +1,109 @@
1
+ import type { Page } from "@playwright/test";
2
+
3
+ export interface ShowCommentaryOptions {
4
+ selector: string;
5
+ text: string;
6
+ }
7
+
8
+ const TOOLTIP_ID = "demon-commentary-tooltip";
9
+
10
+ export async function showCommentary(
11
+ page: Page,
12
+ options: ShowCommentaryOptions,
13
+ ): Promise<void> {
14
+ await page.evaluate(
15
+ ({ selector, text, tooltipId }) => {
16
+ const target = document.querySelector(selector);
17
+ if (!target) {
18
+ throw new Error(
19
+ `demon commentary: element not found for selector "${selector}"`,
20
+ );
21
+ }
22
+
23
+ // Remove any existing tooltip
24
+ document.getElementById(tooltipId)?.remove();
25
+
26
+ const rect = target.getBoundingClientRect();
27
+
28
+ const tooltip = document.createElement("div");
29
+ tooltip.id = tooltipId;
30
+ tooltip.textContent = text;
31
+
32
+ const style = document.createElement("style");
33
+ style.setAttribute("data-demon-commentary", "");
34
+ style.textContent = `
35
+ @keyframes demon-commentary-in {
36
+ from {
37
+ opacity: 0;
38
+ transform: translateY(8px);
39
+ }
40
+ to {
41
+ opacity: 1;
42
+ transform: translateY(0);
43
+ }
44
+ }
45
+ @keyframes demon-commentary-out {
46
+ from {
47
+ opacity: 1;
48
+ transform: translateY(0);
49
+ }
50
+ to {
51
+ opacity: 0;
52
+ transform: translateY(8px);
53
+ }
54
+ }
55
+ #${tooltipId} {
56
+ position: fixed;
57
+ z-index: 2147483647;
58
+ background: #1a1a2e;
59
+ color: #eee;
60
+ padding: 8px 14px;
61
+ border-radius: 6px;
62
+ font: 14px/1.4 system-ui, sans-serif;
63
+ max-width: 320px;
64
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
65
+ pointer-events: none;
66
+ animation: demon-commentary-in 0.3s ease-out forwards;
67
+ }
68
+ #${tooltipId}.demon-commentary-hiding {
69
+ animation: demon-commentary-out 0.25s ease-in forwards;
70
+ }
71
+ `;
72
+
73
+ // Remove previous style if any
74
+ document.querySelector("style[data-demon-commentary]")?.remove();
75
+ document.head.appendChild(style);
76
+
77
+ // Position below the target element, horizontally centered
78
+ const top = rect.bottom + 10;
79
+ const left = rect.left + rect.width / 2;
80
+ tooltip.style.top = `${top}px`;
81
+ tooltip.style.left = `${left}px`;
82
+ tooltip.style.transform = `translateX(-50%)`;
83
+
84
+ document.body.appendChild(tooltip);
85
+ },
86
+ { selector: options.selector, text: options.text, tooltipId: TOOLTIP_ID },
87
+ );
88
+ }
89
+
90
+ export async function hideCommentary(page: Page): Promise<void> {
91
+ await page.evaluate((tooltipId) => {
92
+ const tooltip = document.getElementById(tooltipId);
93
+ if (!tooltip) return;
94
+
95
+ tooltip.classList.add("demon-commentary-hiding");
96
+
97
+ tooltip.addEventListener(
98
+ "animationend",
99
+ () => {
100
+ tooltip.remove();
101
+ document.querySelector("style[data-demon-commentary]")?.remove();
102
+ },
103
+ { once: true },
104
+ );
105
+ }, TOOLTIP_ID);
106
+
107
+ // Wait for the animate-out to complete
108
+ await page.waitForTimeout(300);
109
+ }
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
- export {};
1
+ export { showCommentary, hideCommentary } from "./commentary.ts";
2
+ export type { ShowCommentaryOptions } from "./commentary.ts";
package/tsconfig.json DELETED
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "lib": ["ESNext"],
4
- "module": "ESNext",
5
- "target": "ESNext",
6
- "moduleResolution": "bundler",
7
- "moduleDetection": "force",
8
- "allowImportingTsExtensions": true,
9
- "verbatimModuleSyntax": true,
10
- "noEmit": true,
11
- "strict": true,
12
- "skipLibCheck": true,
13
- "noFallthroughCasesInSwitch": true,
14
- "noUnusedLocals": true,
15
- "noUnusedParameters": true,
16
- "noPropertyAccessFromIndexSignature": true
17
- }
18
- }