pw-core 1.2.0 → 1.3.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 (86) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +777 -0
  4. package/dist/codegen/config/context-weights.d.ts +8 -0
  5. package/dist/codegen/config/context-weights.js +11 -0
  6. package/dist/codegen/config/ignored-attributes.d.ts +1 -0
  7. package/dist/codegen/config/ignored-attributes.js +4 -0
  8. package/dist/codegen/config/ignored-classes.d.ts +1 -0
  9. package/dist/codegen/config/ignored-classes.js +144 -0
  10. package/dist/codegen/config/ignored-values.d.ts +1 -0
  11. package/dist/codegen/config/ignored-values.js +4 -0
  12. package/dist/codegen/config/index.d.ts +29 -0
  13. package/dist/codegen/config/index.js +17 -0
  14. package/dist/codegen/config/strategy-order.d.ts +1 -0
  15. package/dist/codegen/config/strategy-order.js +18 -0
  16. package/dist/codegen/config/weights.d.ts +15 -0
  17. package/dist/codegen/config/weights.js +18 -0
  18. package/dist/codegen/floating-panel/client.d.ts +1 -0
  19. package/dist/codegen/floating-panel/client.js +248 -0
  20. package/dist/codegen/floating-panel/index.d.ts +4 -0
  21. package/dist/codegen/floating-panel/index.js +20 -0
  22. package/dist/codegen/floating-panel/manager.d.ts +19 -0
  23. package/dist/codegen/floating-panel/manager.js +90 -0
  24. package/dist/codegen/floating-panel/template.d.ts +2 -0
  25. package/dist/codegen/floating-panel/template.js +58 -0
  26. package/dist/codegen/floating-panel/types.d.ts +7 -0
  27. package/dist/codegen/floating-panel/types.js +2 -0
  28. package/dist/codegen/generator/action.validator.d.ts +5 -0
  29. package/dist/codegen/generator/action.validator.js +27 -0
  30. package/dist/codegen/generator/index.d.ts +13 -0
  31. package/dist/codegen/generator/index.js +724 -0
  32. package/dist/codegen/generator/locator.restricted.d.ts +36 -0
  33. package/dist/codegen/generator/locator.restricted.js +127 -0
  34. package/dist/codegen/generator/locator.validator.d.ts +8 -0
  35. package/dist/codegen/generator/locator.validator.js +38 -0
  36. package/dist/codegen/hover-tracker/client.d.ts +1 -0
  37. package/dist/codegen/hover-tracker/client.js +75 -0
  38. package/dist/codegen/hover-tracker/index.d.ts +3 -0
  39. package/dist/codegen/hover-tracker/index.js +19 -0
  40. package/dist/codegen/hover-tracker/manager.d.ts +11 -0
  41. package/dist/codegen/hover-tracker/manager.js +28 -0
  42. package/dist/codegen/hover-tracker/types.d.ts +3 -0
  43. package/dist/codegen/hover-tracker/types.js +2 -0
  44. package/dist/codegen/index.d.ts +35 -0
  45. package/dist/codegen/index.js +1147 -0
  46. package/dist/codegen/key-utils.d.ts +23 -0
  47. package/dist/codegen/key-utils.js +68 -0
  48. package/dist/codegen/scorer/base-score.d.ts +1 -0
  49. package/dist/codegen/scorer/base-score.js +7 -0
  50. package/dist/codegen/scorer/context-score.d.ts +2 -0
  51. package/dist/codegen/scorer/context-score.js +27 -0
  52. package/dist/codegen/scorer/index.d.ts +5 -0
  53. package/dist/codegen/scorer/index.js +23 -0
  54. package/dist/codegen/scorer/locator.ranking.d.ts +15 -0
  55. package/dist/codegen/scorer/locator.ranking.js +83 -0
  56. package/dist/codegen/scorer/semantic-score.d.ts +1 -0
  57. package/dist/codegen/scorer/semantic-score.js +47 -0
  58. package/dist/codegen/types.d.ts +35 -0
  59. package/dist/codegen/types.js +2 -0
  60. package/dist/component/table.js +14 -10
  61. package/dist/constants/methods.d.ts +2 -0
  62. package/dist/constants/methods.js +33 -0
  63. package/dist/constants/strategies.d.ts +2 -0
  64. package/dist/constants/strategies.js +47 -0
  65. package/dist/page/actions/locator-actions.js +15 -4
  66. package/dist/page/assertions/verify-chain.d.ts +39 -32
  67. package/dist/page/assertions/verify-chain.js +18 -4
  68. package/dist/page/assertions/verify-helpers.js +12 -3
  69. package/dist/page/config.d.ts +109 -71
  70. package/dist/page/config.js +10 -31
  71. package/dist/page/locators/dynamic-locator-resolver.js +29 -9
  72. package/dist/page/locators/resolver.d.ts +15 -15
  73. package/dist/page/locators/resolver.js +151 -32
  74. package/dist/page/registry.d.ts +43 -6
  75. package/dist/page/registry.js +90 -18
  76. package/dist/page/typed-page.d.ts +33 -29
  77. package/dist/page/typed-page.js +40 -11
  78. package/dist/page/types/proxy-methods.d.ts +69 -54
  79. package/dist/page/types/validation.d.ts +48 -1
  80. package/dist/page/utils/caller-location.js +13 -9
  81. package/dist/page/utils/formatter.js +6 -3
  82. package/dist/types/methods.d.ts +4 -0
  83. package/dist/types/methods.js +2 -0
  84. package/dist/types/strategies.d.ts +17 -0
  85. package/dist/types/strategies.js +2 -0
  86. package/package.json +8 -1
@@ -0,0 +1,8 @@
1
+ export declare const CONTEXT_WEIGHTS: {
2
+ siblingText: number;
3
+ parentText: number;
4
+ heading: number;
5
+ label: number;
6
+ accessibleName: number;
7
+ semanticParent: number;
8
+ };
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONTEXT_WEIGHTS = void 0;
4
+ exports.CONTEXT_WEIGHTS = {
5
+ siblingText: 15,
6
+ parentText: 15,
7
+ heading: 10,
8
+ label: 20,
9
+ accessibleName: 20,
10
+ semanticParent: 10
11
+ };
@@ -0,0 +1 @@
1
+ export declare const IGNORED_ATTRIBUTES: string[];
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IGNORED_ATTRIBUTES = void 0;
4
+ exports.IGNORED_ATTRIBUTES = ['style', 'onclick', 'onchange', 'tabindex', 'aria-hidden', 'disabled', 'checked'];
@@ -0,0 +1 @@
1
+ export declare const IGNORED_CLASS_PATTERNS: RegExp[];
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IGNORED_CLASS_PATTERNS = void 0;
4
+ exports.IGNORED_CLASS_PATTERNS = [
5
+ // ── Exact standalone utility classes ──
6
+ /^flex$/,
7
+ /^grid$/,
8
+ /^block$/,
9
+ /^inline$/,
10
+ /^inline-block$/,
11
+ /^inline-flex$/,
12
+ /^inline-grid$/,
13
+ /^hidden$/,
14
+ /^visible$/,
15
+ /^invisible$/,
16
+ /^relative$/,
17
+ /^absolute$/,
18
+ /^fixed$/,
19
+ /^sticky$/,
20
+ /^static$/,
21
+ /^overflow-/,
22
+ /^cursor-/,
23
+ /^pointer-events-/,
24
+ /^select-/,
25
+ /^resize$/,
26
+ /^table$/,
27
+ /^contents$/,
28
+ // ── Tailwind / utility spacing ──
29
+ /^m-/,
30
+ /^mt-/,
31
+ /^mr-/,
32
+ /^mb-/,
33
+ /^ml-/,
34
+ /^mx-/,
35
+ /^my-/,
36
+ /^-m/,
37
+ /^p-/,
38
+ /^pt-/,
39
+ /^pr-/,
40
+ /^pb-/,
41
+ /^pl-/,
42
+ /^px-/,
43
+ /^py-/,
44
+ /^gap-/,
45
+ /^space-/,
46
+ // ── Typography utilities ──
47
+ /^text-/,
48
+ /^font-/,
49
+ /^fw-/,
50
+ /^fst-/,
51
+ /^lh-/,
52
+ /^leading-/,
53
+ /^tracking-/,
54
+ /^whitespace-/,
55
+ /^break-/,
56
+ /^truncate$/,
57
+ // ── Colors / backgrounds ──
58
+ /^bg-/,
59
+ /^from-/,
60
+ /^via-/,
61
+ /^to-/,
62
+ /^text-opacity-/,
63
+ /^bg-opacity-/,
64
+ // ── Borders / rounded ──
65
+ /^border/,
66
+ /^rounded/,
67
+ /^ring-/,
68
+ /^outline-/,
69
+ /^divide-/,
70
+ // ── Layout utilities ──
71
+ /^d-/,
72
+ /^flex-/,
73
+ /^grid-/,
74
+ /^col-/,
75
+ /^row-/,
76
+ /^container/,
77
+ /^w-/,
78
+ /^h-/,
79
+ /^min-/,
80
+ /^max-/,
81
+ /^size-/,
82
+ /^aspect-/,
83
+ /^grow$/,
84
+ /^shrink$/,
85
+ /^basis-/,
86
+ /^order-/,
87
+ /^self-/,
88
+ // ── Flex / grid alignment ──
89
+ /^justify-/,
90
+ /^align-/,
91
+ /^items-/,
92
+ /^content-/,
93
+ /^place-/,
94
+ // ── Transforms / transitions / animations ──
95
+ /^transform/,
96
+ /^transition/,
97
+ /^duration-/,
98
+ /^ease-/,
99
+ /^delay-/,
100
+ /^animate-/,
101
+ /^translate-/,
102
+ /^rotate-/,
103
+ /^scale-/,
104
+ /^skew-/,
105
+ /^origin-/,
106
+ // ── Effects / filters ──
107
+ /^shadow/,
108
+ /^opacity-/,
109
+ /^blur-/,
110
+ /^brightness-/,
111
+ /^contrast-/,
112
+ /^drop-shadow-/,
113
+ /^grayscale/,
114
+ /^invert/,
115
+ /^saturate-/,
116
+ /^sepia/,
117
+ /^backdrop-/,
118
+ // ── Z-index / position ──
119
+ /^z-/,
120
+ /^inset-/,
121
+ /^top-/,
122
+ /^right-/,
123
+ /^bottom-/,
124
+ /^left-/,
125
+ // ── Bootstrap components ──
126
+ /^btn/,
127
+ /^alert-/,
128
+ /^card-/,
129
+ /^nav-/,
130
+ /^badge-/,
131
+ /^modal-/,
132
+ // ── Framework-generated class prefixes ──
133
+ /^Mui/,
134
+ /^css-/,
135
+ /^sc-/,
136
+ /^chakra-/,
137
+ /^emotion-/,
138
+ /^ant-/,
139
+ /^ng-/,
140
+ /^jsx-/,
141
+ /^svelte-/,
142
+ /^_/,
143
+ /^[a-z]{1,2}\d{3,}/ // e.g. "a1b2c3" auto-generated hashes
144
+ ];
@@ -0,0 +1 @@
1
+ export declare const IGNORED_VALUES: string[];
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IGNORED_VALUES = void 0;
4
+ exports.IGNORED_VALUES = ['', 'true', 'false', 'yes', 'no', 'null', 'undefined', '0', '1'];
@@ -0,0 +1,29 @@
1
+ export declare const codegenConfig: {
2
+ weights: {
3
+ testId: number;
4
+ id: number;
5
+ idAttribute: number;
6
+ dataAttribute: number;
7
+ className: number;
8
+ role: number;
9
+ label: number;
10
+ placeholder: number;
11
+ altText: number;
12
+ title: number;
13
+ text: number;
14
+ css: number;
15
+ xpath: number;
16
+ };
17
+ contextWeights: {
18
+ siblingText: number;
19
+ parentText: number;
20
+ heading: number;
21
+ label: number;
22
+ accessibleName: number;
23
+ semanticParent: number;
24
+ };
25
+ ignoredValues: string[];
26
+ ignoredAttributes: string[];
27
+ ignoredClasses: RegExp[];
28
+ strategyOrder: string[];
29
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codegenConfig = void 0;
4
+ const weights_1 = require("./weights");
5
+ const context_weights_1 = require("./context-weights");
6
+ const strategy_order_1 = require("./strategy-order");
7
+ const ignored_values_1 = require("./ignored-values");
8
+ const ignored_attributes_1 = require("./ignored-attributes");
9
+ const ignored_classes_1 = require("./ignored-classes");
10
+ exports.codegenConfig = {
11
+ weights: weights_1.LOCATOR_WEIGHTS,
12
+ contextWeights: context_weights_1.CONTEXT_WEIGHTS,
13
+ ignoredValues: ignored_values_1.IGNORED_VALUES,
14
+ ignoredAttributes: ignored_attributes_1.IGNORED_ATTRIBUTES,
15
+ ignoredClasses: ignored_classes_1.IGNORED_CLASS_PATTERNS,
16
+ strategyOrder: strategy_order_1.STRATEGY_ORDER
17
+ };
@@ -0,0 +1 @@
1
+ export declare const STRATEGY_ORDER: string[];
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STRATEGY_ORDER = void 0;
4
+ exports.STRATEGY_ORDER = [
5
+ 'testId',
6
+ 'id',
7
+ 'idAttribute',
8
+ 'dataAttribute',
9
+ 'className',
10
+ 'role',
11
+ 'label',
12
+ 'placeholder',
13
+ 'altText',
14
+ 'title',
15
+ 'text',
16
+ 'css',
17
+ 'xpath'
18
+ ];
@@ -0,0 +1,15 @@
1
+ export declare const LOCATOR_WEIGHTS: {
2
+ testId: number;
3
+ id: number;
4
+ idAttribute: number;
5
+ dataAttribute: number;
6
+ className: number;
7
+ role: number;
8
+ label: number;
9
+ placeholder: number;
10
+ altText: number;
11
+ title: number;
12
+ text: number;
13
+ css: number;
14
+ xpath: number;
15
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOCATOR_WEIGHTS = void 0;
4
+ exports.LOCATOR_WEIGHTS = {
5
+ testId: 100,
6
+ id: 90,
7
+ idAttribute: 80,
8
+ dataAttribute: 75,
9
+ className: 60,
10
+ role: 50,
11
+ label: 40,
12
+ placeholder: 35,
13
+ altText: 33,
14
+ title: 32,
15
+ text: 20,
16
+ css: 10,
17
+ xpath: 1
18
+ };
@@ -0,0 +1 @@
1
+ export declare function clientInjectFloatingPanel(idx: string, fileName: string, hasSteps: boolean, cssStyle: string, htmlContent: string): void;
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clientInjectFloatingPanel = clientInjectFloatingPanel;
4
+ function clientInjectFloatingPanel(idx, fileName, hasSteps, cssStyle, htmlContent) {
5
+ if (!document.body) {
6
+ setTimeout(() => clientInjectFloatingPanel(idx, fileName, hasSteps, cssStyle, htmlContent), 50);
7
+ return;
8
+ }
9
+ let sessionHasSteps = false;
10
+ try {
11
+ sessionHasSteps = sessionStorage.getItem('pw-core-has-steps') === 'true';
12
+ }
13
+ catch (e) { }
14
+ const effectiveHasSteps = hasSteps || sessionHasSteps;
15
+ if (effectiveHasSteps) {
16
+ try {
17
+ sessionStorage.setItem('pw-core-has-steps', 'true');
18
+ }
19
+ catch (e) { }
20
+ }
21
+ const numEl = document.getElementById('pw-core-test-num');
22
+ const existingNewTestBtn = document.getElementById('pw-core-new-test-btn');
23
+ const existingNewSerialBtn = document.getElementById('pw-core-new-serial-btn');
24
+ if (existingNewTestBtn) {
25
+ if (effectiveHasSteps) {
26
+ existingNewTestBtn.disabled = false;
27
+ existingNewTestBtn.removeAttribute('disabled');
28
+ existingNewTestBtn.style.opacity = '1';
29
+ existingNewTestBtn.style.cursor = 'pointer';
30
+ existingNewTestBtn.title = 'Start new test recording (new page/file)';
31
+ }
32
+ else {
33
+ existingNewTestBtn.disabled = true;
34
+ existingNewTestBtn.setAttribute('disabled', 'true');
35
+ existingNewTestBtn.style.opacity = '0.35';
36
+ existingNewTestBtn.style.cursor = 'not-allowed';
37
+ existingNewTestBtn.title = 'Disabled: Record at least one action/assertion to start a new test';
38
+ }
39
+ }
40
+ if (existingNewSerialBtn) {
41
+ if (effectiveHasSteps) {
42
+ existingNewSerialBtn.disabled = false;
43
+ existingNewSerialBtn.removeAttribute('disabled');
44
+ existingNewSerialBtn.style.opacity = '1';
45
+ existingNewSerialBtn.style.cursor = 'pointer';
46
+ existingNewSerialBtn.title = 'Add serial test (continues on same page)';
47
+ }
48
+ else {
49
+ existingNewSerialBtn.disabled = true;
50
+ existingNewSerialBtn.setAttribute('disabled', 'true');
51
+ existingNewSerialBtn.style.opacity = '0.35';
52
+ existingNewSerialBtn.style.cursor = 'not-allowed';
53
+ existingNewSerialBtn.title = 'Disabled: Record at least one action/assertion to add a serial test';
54
+ }
55
+ }
56
+ if (numEl) {
57
+ numEl.textContent = '#' + idx;
58
+ return;
59
+ }
60
+ // Remove existing panel to re-inject with updated index
61
+ const existing = document.getElementById('pw-core-codegen-panel');
62
+ if (existing)
63
+ existing.remove();
64
+ const div = document.createElement('div');
65
+ div.id = 'pw-core-codegen-panel';
66
+ div.setAttribute('data-pw-core-panel', 'true');
67
+ div.style.cssText = [
68
+ 'position:fixed',
69
+ 'top:0px',
70
+ 'left:35%',
71
+ 'z-index:2147483647',
72
+ 'display:flex',
73
+ 'align-items:center',
74
+ 'gap:0',
75
+ 'background:rgba(255,255,255,0.867)',
76
+ 'box-shadow: rgba(0, 0, 0, 0.1) 0px 5px 5px',
77
+ 'backdrop-filter:blur(8px)',
78
+ '-webkit-backdrop-filter:blur(8px)',
79
+ 'border:1px solid rgba(0,0,0,0.12)',
80
+ 'border-radius:4px',
81
+ 'font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif',
82
+ 'color:#000',
83
+ 'user-select:none',
84
+ 'pointer-events:all',
85
+ 'cursor:grab',
86
+ 'overflow:hidden'
87
+ ].join(';');
88
+ const styleEl = document.createElement('style');
89
+ styleEl.textContent = cssStyle;
90
+ div.appendChild(styleEl);
91
+ // Create temporary container to parse htmlContent
92
+ const temp = document.createElement('div');
93
+ temp.innerHTML = htmlContent;
94
+ while (temp.firstChild) {
95
+ div.appendChild(temp.firstChild);
96
+ }
97
+ document.body.appendChild(div);
98
+ // Drag logic — constrained to top edge only
99
+ let dragging = false;
100
+ let dragStartX = 0;
101
+ let startLeft = 0;
102
+ const dragHandle = document.getElementById('pw-core-drag-handle');
103
+ const onMouseDown = (e) => {
104
+ dragging = true;
105
+ dragStartX = e.clientX;
106
+ const rect = div.getBoundingClientRect();
107
+ startLeft = rect.left;
108
+ div.style.cursor = 'grabbing';
109
+ if (dragHandle)
110
+ dragHandle.style.cursor = 'grabbing';
111
+ e.preventDefault();
112
+ };
113
+ const onMouseMove = (e) => {
114
+ if (!dragging)
115
+ return;
116
+ const dx = e.clientX - dragStartX;
117
+ const newLeft = Math.max(0, Math.min(window.innerWidth - div.offsetWidth, startLeft + dx));
118
+ div.style.left = newLeft + 'px';
119
+ };
120
+ const onMouseUp = () => {
121
+ dragging = false;
122
+ div.style.cursor = 'grab';
123
+ if (dragHandle)
124
+ dragHandle.style.cursor = 'grab';
125
+ };
126
+ if (dragHandle)
127
+ dragHandle.addEventListener('mousedown', onMouseDown);
128
+ document.addEventListener('mousemove', onMouseMove);
129
+ document.addEventListener('mouseup', onMouseUp);
130
+ const enableButtons = () => {
131
+ try {
132
+ sessionStorage.setItem('pw-core-has-steps', 'true');
133
+ }
134
+ catch (e) { }
135
+ const newTestBtn = document.getElementById('pw-core-new-test-btn');
136
+ const newSerialBtn = document.getElementById('pw-core-new-serial-btn');
137
+ if (newTestBtn && newTestBtn.disabled) {
138
+ newTestBtn.disabled = false;
139
+ newTestBtn.removeAttribute('disabled');
140
+ newTestBtn.style.opacity = '1';
141
+ newTestBtn.style.cursor = 'pointer';
142
+ newTestBtn.title = 'Start new test recording (new page/file)';
143
+ }
144
+ if (newSerialBtn && newSerialBtn.disabled) {
145
+ newSerialBtn.disabled = false;
146
+ newSerialBtn.removeAttribute('disabled');
147
+ newSerialBtn.style.opacity = '1';
148
+ newSerialBtn.style.cursor = 'pointer';
149
+ newSerialBtn.title = 'Add serial test (continues on same page)';
150
+ }
151
+ };
152
+ // Auto-enable buttons instantly on any page interaction
153
+ document.addEventListener('click', (e) => {
154
+ if (e.target && e.target.closest('#pw-core-codegen-panel'))
155
+ return;
156
+ enableButtons();
157
+ }, { capture: true, passive: true });
158
+ document.addEventListener('keydown', (e) => {
159
+ if (e.target && e.target.closest('#pw-core-codegen-panel'))
160
+ return;
161
+ enableButtons();
162
+ }, { capture: true, passive: true });
163
+ document.addEventListener('input', (e) => {
164
+ if (e.target && e.target.closest('#pw-core-codegen-panel'))
165
+ return;
166
+ enableButtons();
167
+ }, { capture: true, passive: true });
168
+ const optimisticUpdate = (type) => {
169
+ const numEl = document.getElementById('pw-core-test-num');
170
+ if (numEl) {
171
+ const current = numEl.textContent || '';
172
+ const clean = current.replace('#', '');
173
+ if (type === 'test') {
174
+ const parts = clean.split('.');
175
+ const nextMajor = parseInt(parts[0], 10) + 1;
176
+ numEl.textContent = '#' + nextMajor;
177
+ }
178
+ else {
179
+ const parts = clean.split('.');
180
+ if (parts.length === 1) {
181
+ numEl.textContent = '#' + parts[0] + '.2';
182
+ }
183
+ else {
184
+ const nextMinor = (parseInt(parts[1], 10) || 1) + 1;
185
+ numEl.textContent = '#' + parts[0] + '.' + nextMinor;
186
+ }
187
+ }
188
+ }
189
+ const newTestBtn = document.getElementById('pw-core-new-test-btn');
190
+ const newSerialBtn = document.getElementById('pw-core-new-serial-btn');
191
+ if (newTestBtn) {
192
+ newTestBtn.disabled = true;
193
+ newTestBtn.setAttribute('disabled', 'true');
194
+ newTestBtn.style.opacity = '0.35';
195
+ newTestBtn.style.cursor = 'not-allowed';
196
+ }
197
+ if (newSerialBtn) {
198
+ newSerialBtn.disabled = true;
199
+ newSerialBtn.setAttribute('disabled', 'true');
200
+ newSerialBtn.style.opacity = '0.35';
201
+ newSerialBtn.style.cursor = 'not-allowed';
202
+ }
203
+ };
204
+ div.addEventListener('click', (e) => {
205
+ const target = e.target;
206
+ if (!target)
207
+ return;
208
+ const btn = target.closest('.__pw-btn');
209
+ if (!btn || btn.disabled)
210
+ return;
211
+ e.preventDefault();
212
+ e.stopPropagation();
213
+ if (btn.id === 'pw-core-new-test-btn') {
214
+ try {
215
+ sessionStorage.removeItem('pw-core-has-steps');
216
+ }
217
+ catch (err) { }
218
+ optimisticUpdate('test');
219
+ const trigger = () => {
220
+ if (window.__pwCoreStartNewTest) {
221
+ ;
222
+ window.__pwCoreStartNewTest();
223
+ }
224
+ else {
225
+ setTimeout(trigger, 50);
226
+ }
227
+ };
228
+ trigger();
229
+ }
230
+ else if (btn.id === 'pw-core-new-serial-btn') {
231
+ try {
232
+ sessionStorage.removeItem('pw-core-has-steps');
233
+ }
234
+ catch (err) { }
235
+ optimisticUpdate('serial');
236
+ const trigger = () => {
237
+ if (window.__pwCoreStartNewSerialTest) {
238
+ ;
239
+ window.__pwCoreStartNewSerialTest();
240
+ }
241
+ else {
242
+ setTimeout(trigger, 50);
243
+ }
244
+ };
245
+ trigger();
246
+ }
247
+ });
248
+ }
@@ -0,0 +1,4 @@
1
+ export * from './types';
2
+ export * from './template';
3
+ export * from './client';
4
+ export * from './manager';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./template"), exports);
19
+ __exportStar(require("./client"), exports);
20
+ __exportStar(require("./manager"), exports);
@@ -0,0 +1,19 @@
1
+ import { BrowserContext, Page } from '@playwright/test';
2
+ import { FloatingPanelOptions } from './types';
3
+ export declare class FloatingPanelManager {
4
+ private context;
5
+ private options;
6
+ constructor(context: BrowserContext, options: FloatingPanelOptions);
7
+ /**
8
+ * Set up all required floating panel logic, including exposing callbacks and page event listeners.
9
+ */
10
+ initialize(): Promise<void>;
11
+ /**
12
+ * Inject or update the floating panel on a single page.
13
+ */
14
+ inject(page: Page): Promise<void>;
15
+ /**
16
+ * Helper to inject or update the panel on all active pages.
17
+ */
18
+ injectAll(): Promise<void>;
19
+ }
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FloatingPanelManager = void 0;
4
+ const template_1 = require("./template");
5
+ const client_1 = require("./client");
6
+ class FloatingPanelManager {
7
+ context;
8
+ options;
9
+ constructor(context, options) {
10
+ this.context = context;
11
+ this.options = options;
12
+ }
13
+ /**
14
+ * Set up all required floating panel logic, including exposing callbacks and page event listeners.
15
+ */
16
+ async initialize() {
17
+ // 1. Expose functions to the browser context
18
+ await this.context.exposeFunction('__pwCoreGetTestIndex', () => {
19
+ return this.options.getDisplayTestIndex();
20
+ });
21
+ await this.context.exposeFunction('__pwCoreStartNewTest', () => {
22
+ console.log('DEBUG [cli]: __pwCoreStartNewTest exposed function called in browser context');
23
+ return this.options.onStartNewTest();
24
+ });
25
+ await this.context.exposeFunction('__pwCoreStartNewSerialTest', () => {
26
+ console.log('DEBUG [cli]: __pwCoreStartNewSerialTest exposed function called in browser context');
27
+ return this.options.onStartNewSerialTest();
28
+ });
29
+ // 2. Listen for page events to automatically inject the panel
30
+ this.context.on('page', (p) => {
31
+ p.on('load', () => this.inject(p).catch(() => { }));
32
+ p.on('domcontentloaded', () => this.inject(p).catch(() => { }));
33
+ p.on('framenavigated', (frame) => {
34
+ if (frame === p.mainFrame()) {
35
+ // Wait briefly for SPA framework to mount before injecting/updating
36
+ setTimeout(() => {
37
+ this.inject(p).catch(() => { });
38
+ }, 200);
39
+ }
40
+ });
41
+ });
42
+ }
43
+ /**
44
+ * Inject or update the floating panel on a single page.
45
+ */
46
+ async inject(page) {
47
+ try {
48
+ const idx = this.options.getDisplayTestIndex();
49
+ const fileName = this.options.getOutputFileName();
50
+ const hasSteps = this.options.hasSteps();
51
+ const newTestTitle = hasSteps
52
+ ? 'Start new test recording (new page/file)'
53
+ : 'Disabled: Record at least one action/assertion to start a new test';
54
+ const newSerialTitle = hasSteps
55
+ ? 'Add serial test (continues on same page)'
56
+ : 'Disabled: Record at least one action/assertion to add a serial test';
57
+ const disabledAttr = hasSteps ? '' : ' disabled style="opacity:0.35; cursor:not-allowed;"';
58
+ const htmlContent = (0, template_1.getFloatingPanelHtml)(idx, fileName, newTestTitle, newSerialTitle, disabledAttr);
59
+ const fnStr = client_1.clientInjectFloatingPanel.toString();
60
+ // Evaluate the client injection function in the page context
61
+ await page
62
+ .evaluate(({ idx, fileName, hasSteps, cssStyle, htmlContent, fnStr }) => {
63
+ const fn = new Function(`return ${fnStr}`)();
64
+ fn(idx, fileName, hasSteps, cssStyle, htmlContent);
65
+ }, {
66
+ idx,
67
+ fileName,
68
+ hasSteps,
69
+ cssStyle: template_1.FLOATING_PANEL_STYLE,
70
+ htmlContent,
71
+ fnStr
72
+ })
73
+ .catch((err) => {
74
+ console.error(`DEBUG [cli]: Failed to inject/update floating panel on page ${page.url()}:`, err);
75
+ });
76
+ }
77
+ catch (err) {
78
+ console.error(`DEBUG [cli]: Exception in injectFloatingPanel wrapper:`, err);
79
+ }
80
+ }
81
+ /**
82
+ * Helper to inject or update the panel on all active pages.
83
+ */
84
+ async injectAll() {
85
+ for (const p of this.context.pages()) {
86
+ await this.inject(p).catch(() => { });
87
+ }
88
+ }
89
+ }
90
+ exports.FloatingPanelManager = FloatingPanelManager;