playwright-cucumber-ts-steps 1.1.7 → 1.1.8

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 (52) hide show
  1. package/dist/backend/actions/click.d.ts +2 -0
  2. package/dist/backend/actions/click.d.ts.map +1 -0
  3. package/dist/backend/actions/click.js +179 -0
  4. package/dist/backend/actions/find.d.ts +2 -0
  5. package/dist/backend/actions/find.d.ts.map +1 -0
  6. package/dist/backend/actions/find.js +291 -0
  7. package/dist/backend/actions/form.d.ts +2 -0
  8. package/dist/backend/actions/form.d.ts.map +1 -0
  9. package/dist/backend/actions/form.js +185 -0
  10. package/dist/backend/actions/formTable.js +1 -1
  11. package/dist/backend/actions/frames.d.ts +2 -0
  12. package/dist/backend/actions/frames.d.ts.map +1 -0
  13. package/dist/backend/actions/frames.js +60 -0
  14. package/dist/backend/actions/index.d.ts +10 -0
  15. package/dist/backend/actions/index.d.ts.map +1 -1
  16. package/dist/backend/actions/index.js +10 -0
  17. package/dist/backend/actions/inputs.d.ts +2 -0
  18. package/dist/backend/actions/inputs.d.ts.map +1 -0
  19. package/dist/backend/actions/inputs.js +177 -0
  20. package/dist/backend/actions/keyboard.d.ts +2 -0
  21. package/dist/backend/actions/keyboard.d.ts.map +1 -0
  22. package/dist/backend/actions/keyboard.js +62 -0
  23. package/dist/backend/actions/misc.d.ts +2 -0
  24. package/dist/backend/actions/misc.d.ts.map +1 -0
  25. package/dist/backend/actions/misc.js +144 -0
  26. package/dist/backend/actions/mobile.d.ts +2 -0
  27. package/dist/backend/actions/mobile.d.ts.map +1 -0
  28. package/dist/backend/actions/mobile.js +87 -0
  29. package/dist/backend/actions/mouse.d.ts +2 -0
  30. package/dist/backend/actions/mouse.d.ts.map +1 -0
  31. package/dist/backend/actions/mouse.js +105 -0
  32. package/dist/backend/actions/navigation.js +31 -7
  33. package/dist/backend/actions/waits.d.ts +2 -0
  34. package/dist/backend/actions/waits.d.ts.map +1 -0
  35. package/dist/backend/actions/waits.js +51 -0
  36. package/dist/backend/api/index.d.ts +1 -0
  37. package/dist/backend/api/index.d.ts.map +1 -1
  38. package/dist/backend/api/index.js +1 -0
  39. package/dist/backend/api/network.d.ts +2 -0
  40. package/dist/backend/api/network.d.ts.map +1 -0
  41. package/dist/backend/api/network.js +145 -0
  42. package/dist/backend/assertions/pageState.js +25 -14
  43. package/dist/backend/assertions/visibility.js +116 -12
  44. package/dist/backend/utils/state.d.ts +18 -0
  45. package/dist/backend/utils/state.d.ts.map +1 -0
  46. package/dist/backend/utils/state.js +84 -0
  47. package/dist/core/registry.d.ts +14 -14
  48. package/dist/core/registry.d.ts.map +1 -1
  49. package/dist/core/registry.js +13 -4
  50. package/dist/core/runner.d.ts.map +1 -1
  51. package/dist/core/runner.js +91 -37
  52. package/package.json +1 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=frames.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/frames.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const registry_1 = require("../../core/registry");
4
+ const state_1 = require("../utils/state");
5
+ // =============================
6
+ // IFRAME HANDLING
7
+ // =============================
8
+ /**
9
+ * Switches context to a specific iframe by its selector.
10
+ * Subsequent "I find element" steps will search INSIDE this frame.
11
+ * Pattern: When I switch to frame "#payment-frame"
12
+ */
13
+ (0, registry_1.Step)("I switch to frame {string}", async (page, selector) => {
14
+ const frameElement = page.locator(selector);
15
+ const frame = frameElement.contentFrame();
16
+ // We can't actually "switch" the global 'page' object easily in this architecture,
17
+ // BUT we can store the frame as the "Active Scope" if we extended our state management.
18
+ //
19
+ // SIMPLER APPROACH: We just store the frame locator as the "Active Element"
20
+ // and update our `find` steps to look inside it if it's a frame.
21
+ // However, for strict BDD, it's often easier to just interact with the frame directly here:
22
+ if (!frame)
23
+ throw new Error(`❌ Iframe "${selector}" not found or has no content.`);
24
+ // Set the frame as the active context for future actions?
25
+ // This requires updating `src/backend/utils/state.ts` to support `scope`.
26
+ //
27
+ // For now, let's just Log it. Frame handling usually requires a dedicated `find inside frame` step.
28
+ console.log(`⚠️ Switching Frames requires a Scope manager. For now, use 'I find element ... in frame ...'`);
29
+ });
30
+ /**
31
+ * A specialized finder that looks INSIDE a frame.
32
+ * Pattern: When I find element "#card-number" in frame "#stripe-iframe"
33
+ */
34
+ (0, registry_1.Step)("I find element {string} in frame {string}", async (page, elementSelector, frameSelector) => {
35
+ const frame = page.frameLocator(frameSelector);
36
+ const element = frame.locator(elementSelector).first();
37
+ await element.waitFor();
38
+ (0, state_1.setActiveElement)(page, element);
39
+ console.log(`🔍 Found element "${elementSelector}" inside frame "${frameSelector}"`);
40
+ });
41
+ // =============================
42
+ // TAB / WINDOW HANDLING
43
+ // =============================
44
+ /**
45
+ * Waits for a new tab (popup) to open and brings it to front.
46
+ * Use this after clicking a link with target="_blank".
47
+ * Pattern: When I switch to new tab
48
+ */
49
+ (0, registry_1.Step)("I switch to new tab", async (page) => {
50
+ // This is tricky: Playwright 'page' object passed to steps is usually fixed.
51
+ // To support multi-tab, we'd need to update the Runner to allow swapping the 'page' reference.
52
+ //
53
+ // For a library like this, checking the popup existence is usually enough:
54
+ console.log("⚠️ Multi-tab support requires Runner updates. Verifying popup event only.");
55
+ const popup = await page.waitForEvent("popup");
56
+ await popup.waitForLoadState();
57
+ console.log(`📑 New tab opened: ${await popup.title()}`);
58
+ // Note: We cannot easily "swap" the 'page' variable for subsequent steps
59
+ // without a more complex Global State object.
60
+ });
@@ -1,4 +1,14 @@
1
1
  import "./navigation";
2
2
  import "./interactions";
3
3
  import "./formTable";
4
+ import "./click";
5
+ import "./find";
6
+ import "./inputs";
7
+ import "./form";
8
+ import "./mouse";
9
+ import "./misc";
10
+ import "./mobile";
11
+ import "./waits";
12
+ import "./frames";
13
+ import "./keyboard";
4
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,gBAAgB,CAAC;AACxB,OAAO,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,CAAC;AACtB,OAAO,gBAAgB,CAAC;AACxB,OAAO,aAAa,CAAC;AACrB,OAAO,SAAS,CAAC;AACjB,OAAO,QAAQ,CAAC;AAChB,OAAO,UAAU,CAAC;AAClB,OAAO,QAAQ,CAAC;AAChB,OAAO,SAAS,CAAC;AACjB,OAAO,QAAQ,CAAC;AAChB,OAAO,UAAU,CAAC;AAClB,OAAO,SAAS,CAAC;AACjB,OAAO,UAAU,CAAC;AAClB,OAAO,YAAY,CAAC"}
@@ -3,3 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  require("./navigation");
4
4
  require("./interactions");
5
5
  require("./formTable");
6
+ require("./click");
7
+ require("./find");
8
+ require("./inputs");
9
+ require("./form");
10
+ require("./mouse");
11
+ require("./misc");
12
+ require("./mobile");
13
+ require("./waits");
14
+ require("./frames");
15
+ require("./keyboard");
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=inputs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/inputs.ts"],"names":[],"mappings":""}
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const registry_1 = require("../../core/registry");
4
+ const state_1 = require("../utils/state");
5
+ // =============================
6
+ // 1. TYPING & FILLING
7
+ // =============================
8
+ /**
9
+ * Types text into the currently stored element.
10
+ * Supports aliases (e.g. "@password")
11
+ * Pattern: When I type "hello"
12
+ */
13
+ (0, registry_1.Step)("I type {string}", async (page, textOrAlias, table) => {
14
+ const element = (0, state_1.getActiveElement)(page);
15
+ const options = (0, state_1.parseClickOptions)(table); // Reusing generic options parser
16
+ let text = textOrAlias;
17
+ // Handle Alias
18
+ if (textOrAlias.startsWith("@")) {
19
+ const alias = textOrAlias.slice(1);
20
+ const val = (0, state_1.getVariable)(page, alias);
21
+ if (!val)
22
+ throw new Error(`❌ Alias @${alias} not found.`);
23
+ text = val;
24
+ }
25
+ await element.fill(text, options);
26
+ console.log(`⌨️ Filled element with: "${text}"`);
27
+ });
28
+ /**
29
+ * Types the value stored in a variable (Explicit version).
30
+ * Pattern: When I type stored "userEmail"
31
+ */
32
+ (0, registry_1.Step)("I type stored {string}", async (page, alias, table) => {
33
+ const element = (0, state_1.getActiveElement)(page);
34
+ const options = (0, state_1.parseClickOptions)(table);
35
+ const val = (0, state_1.getVariable)(page, alias);
36
+ if (!val)
37
+ throw new Error(`❌ Alias "${alias}" not found.`);
38
+ await element.fill(val, options);
39
+ console.log(`⌨️ Typed stored value from "${alias}"`);
40
+ });
41
+ /**
42
+ * Slowly types text (mimics real keystrokes).
43
+ * Pattern: When I slowly type "hello"
44
+ */
45
+ (0, registry_1.Step)("I slowly type {string}", async (page, text) => {
46
+ const element = (0, state_1.getActiveElement)(page);
47
+ await element.pressSequentially(text, { delay: 100 });
48
+ console.log(`⌨️ Slowly typed: "${text}"`);
49
+ });
50
+ /**
51
+ * Sets the value directly (Alias for Type, but semantically "Paste").
52
+ * Pattern: When I set value "hello"
53
+ */
54
+ (0, registry_1.Step)("I set value {string}", async (page, value, table) => {
55
+ const element = (0, state_1.getActiveElement)(page);
56
+ const options = (0, state_1.parseClickOptions)(table);
57
+ await element.fill(value, options);
58
+ console.log(`📝 Set value to: "${value}"`);
59
+ });
60
+ /**
61
+ * Clears the input field.
62
+ * Pattern: When I clear input
63
+ */
64
+ (0, registry_1.Step)("I clear", async (page) => {
65
+ const element = (0, state_1.getActiveElement)(page);
66
+ await element.fill("");
67
+ console.log("🧹 Cleared input");
68
+ });
69
+ /**
70
+ * Press a keyboard key.
71
+ * Pattern: When I press "Enter"
72
+ */
73
+ (0, registry_1.Step)("I press {string}", async (page, key) => {
74
+ const element = (0, state_1.getActiveElement)(page);
75
+ await element.press(key);
76
+ console.log(`🎹 Pressed key: "${key}"`);
77
+ });
78
+ // =============================
79
+ // 2. CHECKBOXES & RADIOS
80
+ // =============================
81
+ /**
82
+ * Checks the stored checkbox or radio button.
83
+ * Pattern: When I check
84
+ */
85
+ (0, registry_1.Step)("I check", async (page, table) => {
86
+ const element = (0, state_1.getActiveElement)(page);
87
+ const options = (0, state_1.parseClickOptions)(table);
88
+ await element.check(options);
89
+ console.log("✅ Checked element");
90
+ });
91
+ /**
92
+ * Unchecks the stored checkbox.
93
+ * Pattern: When I uncheck
94
+ */
95
+ (0, registry_1.Step)("I uncheck", async (page, table) => {
96
+ const element = (0, state_1.getActiveElement)(page);
97
+ const options = (0, state_1.parseClickOptions)(table);
98
+ await element.uncheck(options);
99
+ console.log("⬜ Unchecked element");
100
+ });
101
+ /**
102
+ * Legacy Alias: When I check input
103
+ */
104
+ (0, registry_1.Step)("I check input", async (page, table) => {
105
+ const element = (0, state_1.getActiveElement)(page);
106
+ const options = (0, state_1.parseClickOptions)(table);
107
+ await element.check(options);
108
+ console.log("✅ Checked input");
109
+ });
110
+ /**
111
+ * Legacy Alias: When I uncheck input
112
+ */
113
+ (0, registry_1.Step)("I uncheck input", async (page, table) => {
114
+ const element = (0, state_1.getActiveElement)(page);
115
+ const options = (0, state_1.parseClickOptions)(table);
116
+ await element.uncheck(options);
117
+ console.log("⬜ Unchecked input");
118
+ });
119
+ // =============================
120
+ // 3. DROPDOWNS & SELECTS
121
+ // =============================
122
+ /**
123
+ * Selects an option by visible text/label.
124
+ * Pattern: When I select option "United States"
125
+ */
126
+ (0, registry_1.Step)("I select option {string}", async (page, option, table) => {
127
+ const element = (0, state_1.getActiveElement)(page);
128
+ const options = (0, state_1.parseClickOptions)(table);
129
+ // Playwright selects by value or label automatically
130
+ await element.selectOption({ label: option }, options);
131
+ console.log(`🔽 Selected option: "${option}"`);
132
+ });
133
+ // =============================
134
+ // 4. FORMS & FILES
135
+ // =============================
136
+ /**
137
+ * Submits the form containing the current element.
138
+ * If no element is stored, tries to find the first form on page.
139
+ * Pattern: When I submit
140
+ */
141
+ (0, registry_1.Step)("I submit", async (page) => {
142
+ let formLocator;
143
+ try {
144
+ const element = (0, state_1.getActiveElement)(page);
145
+ // Try to find the parent form of the stored element
146
+ formLocator = element.locator("xpath=ancestor-or-self::form");
147
+ }
148
+ catch (e) {
149
+ // If no element stored, find first form on page
150
+ formLocator = page.locator("form").first();
151
+ }
152
+ const count = await formLocator.count();
153
+ if (count === 0) {
154
+ throw new Error("❌ No form found to submit.");
155
+ }
156
+ // Native HTML submit (bypasses some validation, extremely reliable)
157
+ await formLocator.evaluate((f) => f.submit());
158
+ console.log("📨 Submitted form");
159
+ });
160
+ /**
161
+ * Uploads a file to a file input.
162
+ * Pattern: When I upload file "docs/resume.pdf"
163
+ */
164
+ (0, registry_1.Step)("I select file {string}", async (page, filePath) => {
165
+ const element = (0, state_1.getActiveElement)(page);
166
+ await element.setInputFiles(filePath);
167
+ console.log(`📂 Selected file: "${filePath}"`);
168
+ });
169
+ /**
170
+ * Alias for upload.
171
+ * Pattern: When I upload file "..."
172
+ */
173
+ (0, registry_1.Step)("I upload file {string}", async (page, filePath) => {
174
+ const element = (0, state_1.getActiveElement)(page);
175
+ await element.setInputFiles(filePath);
176
+ console.log(`📂 Uploaded file: "${filePath}"`);
177
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=keyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/keyboard.ts"],"names":[],"mappings":""}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const registry_1 = require("../../core/registry");
4
+ const state_1 = require("../utils/state");
5
+ // ==================================================
6
+ // KEYBOARD INTERACTIONS
7
+ // ==================================================
8
+ /**
9
+ * Presses a specific key globally (on the page).
10
+ * Useful for global shortcuts like closing modals (Escape) or scrolling (PageDown).
11
+ * Pattern: When I press key "Enter"
12
+ */
13
+ (0, registry_1.Step)("I press key {string}", async (page, key) => {
14
+ await page.keyboard.press(key);
15
+ console.log(`⌨️ Pressed key: "${key}"`);
16
+ });
17
+ /**
18
+ * Presses a key on the currently stored/active element.
19
+ * Useful for input fields or buttons.
20
+ * Pattern: When I press key "Enter" on element
21
+ */
22
+ (0, registry_1.Step)("I press key {string} on element", async (page, key) => {
23
+ const element = (0, state_1.getActiveElement)(page);
24
+ await element.press(key);
25
+ console.log(`⌨️ Pressed key "${key}" on stored element`);
26
+ });
27
+ /**
28
+ * Types text directly using the keyboard (global typing).
29
+ * Unlike 'I type', this sends keystrokes one by one to the page,
30
+ * regardless of which element is focused.
31
+ * Pattern: When I press keys "Hello World"
32
+ */
33
+ (0, registry_1.Step)("I press keys {string}", async (page, text) => {
34
+ await page.keyboard.type(text);
35
+ console.log(`⌨️ Typed keys: "${text}"`);
36
+ });
37
+ /**
38
+ * Performs a keyboard shortcut (e.g., Ctrl+C, Meta+S).
39
+ * Pattern: When I press shortcut "Control+C"
40
+ */
41
+ (0, registry_1.Step)("I press shortcut {string}", async (page, shortcut) => {
42
+ // Playwright's keyboard.press supports combinations like "Control+KeyC"
43
+ await page.keyboard.press(shortcut);
44
+ console.log(`⌨️ Performed shortcut: "${shortcut}"`);
45
+ });
46
+ /**
47
+ * Holds down a specific key (e.g., Shift) for subsequent actions.
48
+ * Make sure to release it later!
49
+ * Pattern: When I hold down key "Shift"
50
+ */
51
+ (0, registry_1.Step)("I hold down key {string}", async (page, key) => {
52
+ await page.keyboard.down(key);
53
+ console.log(`⬇️ Holding down key: "${key}"`);
54
+ });
55
+ /**
56
+ * Releases a specific key.
57
+ * Pattern: When I release key "Shift"
58
+ */
59
+ (0, registry_1.Step)("I release key {string}", async (page, key) => {
60
+ await page.keyboard.up(key);
61
+ console.log(`⬆️ Released key: "${key}"`);
62
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=misc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"misc.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/misc.ts"],"names":[],"mappings":""}
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const registry_1 = require("../../core/registry");
4
+ const state_1 = require("../utils/state");
5
+ // ==================================================
6
+ // 1. TIMING & WAITS
7
+ // ==================================================
8
+ /**
9
+ * Pauses execution for a set amount of time.
10
+ * Pattern: When I wait for 1000 milliseconds
11
+ */
12
+ (0, registry_1.Step)("I wait for {int} milliseconds", async (page, ms) => {
13
+ await page.waitForTimeout(ms);
14
+ console.log(`⏳ Waited for ${ms}ms`);
15
+ });
16
+ /**
17
+ * Pauses execution for a set amount of seconds.
18
+ * Pattern: When I wait for 5 seconds
19
+ */
20
+ (0, registry_1.Step)("I wait for {int} seconds", async (page, seconds) => {
21
+ await page.waitForTimeout(seconds * 1000);
22
+ console.log(`⏳ Waited for ${seconds}s`);
23
+ });
24
+ // ==================================================
25
+ // 2. DEBUGGING
26
+ // ==================================================
27
+ /**
28
+ * Pauses the test execution and opens the Playwright Inspector.
29
+ * Useful for manual debugging during a run.
30
+ * Pattern: When I pause
31
+ */
32
+ (0, registry_1.Step)("I pause", async (page) => {
33
+ console.log("⏸️ Pausing test execution...");
34
+ await page.pause();
35
+ });
36
+ /**
37
+ * Alias for pause.
38
+ * Pattern: When I debug
39
+ */
40
+ (0, registry_1.Step)("I debug", async (page) => {
41
+ console.log("🐞 Debugging...");
42
+ await page.pause();
43
+ });
44
+ /**
45
+ * Prints a message to the console logs.
46
+ * Pattern: When I log "Hello World"
47
+ */
48
+ (0, registry_1.Step)("I log {string}", async (page, message) => {
49
+ console.log(`📝 LOG: ${message}`);
50
+ });
51
+ // ==================================================
52
+ // 3. FOCUS & BLUR
53
+ // ==================================================
54
+ /**
55
+ * Focuses on the currently stored element.
56
+ * Pattern: When I focus
57
+ */
58
+ (0, registry_1.Step)("I focus", async (page) => {
59
+ const element = (0, state_1.getActiveElement)(page);
60
+ await element.focus();
61
+ console.log("👀 Focused on stored element");
62
+ });
63
+ /**
64
+ * Blurs (un-focuses) the currently stored element.
65
+ * Pattern: When I blur
66
+ */
67
+ (0, registry_1.Step)("I blur", async (page) => {
68
+ const element = (0, state_1.getActiveElement)(page);
69
+ // Playwright doesn't have a direct .blur(), so we use JS evaluation
70
+ await element.evaluate((el) => {
71
+ if (el instanceof HTMLElement)
72
+ el.blur();
73
+ });
74
+ console.log("🌫️ Blurred stored element");
75
+ });
76
+ // ==================================================
77
+ // 4. BROWSER STORAGE (Cookies / Local Storage)
78
+ // ==================================================
79
+ /**
80
+ * Sets a cookie for the current context.
81
+ * Pattern: When I set cookie "session_id" to "12345"
82
+ */
83
+ (0, registry_1.Step)("I set cookie {string} to {string}", async (page, name, value) => {
84
+ const context = page.context();
85
+ const url = page.url();
86
+ // We need a domain or url to set cookies. We use the current page URL.
87
+ await context.addCookies([{ name, value, url }]);
88
+ console.log(`🍪 Set cookie "${name}"`);
89
+ });
90
+ /**
91
+ * Clears all cookies.
92
+ * Pattern: When I clear all cookies
93
+ */
94
+ (0, registry_1.Step)("I clear all cookies", async (page) => {
95
+ const context = page.context();
96
+ await context.clearCookies();
97
+ console.log("🍪 Cleared all cookies");
98
+ });
99
+ /**
100
+ * Sets a Local Storage item.
101
+ * Pattern: When I set local storage item "theme" to "dark"
102
+ */
103
+ (0, registry_1.Step)("I set local storage item {string} to {string}", async (page, key, value) => {
104
+ await page.evaluate(({ k, v }) => localStorage.setItem(k, v), {
105
+ k: key,
106
+ v: value,
107
+ });
108
+ console.log(`📦 Set local storage "${key}" = "${value}"`);
109
+ });
110
+ /**
111
+ * Gets a Local Storage item and prints it.
112
+ * Pattern: When I get local storage item "token"
113
+ */
114
+ (0, registry_1.Step)("I get local storage item {string}", async (page, key) => {
115
+ const value = await page.evaluate((k) => localStorage.getItem(k), key);
116
+ console.log(`📦 Local Storage "${key}": ${value}`);
117
+ });
118
+ /**
119
+ * Clears all Local Storage.
120
+ * Pattern: When I clear local storage
121
+ */
122
+ (0, registry_1.Step)("I clear local storage", async (page) => {
123
+ await page.evaluate(() => localStorage.clear());
124
+ console.log("📦 Cleared local storage");
125
+ });
126
+ /**
127
+ * Sets a Session Storage item.
128
+ * Pattern: When I set session storage item "user" to "admin"
129
+ */
130
+ (0, registry_1.Step)("I set session storage item {string} to {string}", async (page, key, value) => {
131
+ await page.evaluate(({ k, v }) => sessionStorage.setItem(k, v), {
132
+ k: key,
133
+ v: value,
134
+ });
135
+ console.log(`📦 Set session storage "${key}" = "${value}"`);
136
+ });
137
+ /**
138
+ * Clears all Session Storage.
139
+ * Pattern: When I clear session storage
140
+ */
141
+ (0, registry_1.Step)("I clear session storage", async (page) => {
142
+ await page.evaluate(() => sessionStorage.clear());
143
+ console.log("📦 Cleared session storage");
144
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mobile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobile.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/mobile.ts"],"names":[],"mappings":""}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const registry_1 = require("../../core/registry");
4
+ const state_1 = require("../utils/state");
5
+ /**
6
+ * Helper: Tries to tap. If the context doesn't support touch, falls back to click.
7
+ */
8
+ async function safeTap(target) {
9
+ try {
10
+ // Try native touch tap
11
+ await target.tap();
12
+ return "tapped";
13
+ }
14
+ catch (error) {
15
+ if (error.message.includes("does not support tap")) {
16
+ // Fallback for Desktop Contexts
17
+ await target.click();
18
+ return "clicked (fallback)";
19
+ }
20
+ throw error;
21
+ }
22
+ }
23
+ // ==================================================
24
+ // 1. TOUCH INTERACTIONS
25
+ // ==================================================
26
+ /**
27
+ * Taps on the currently stored element.
28
+ * Pattern: When I tap
29
+ */
30
+ (0, registry_1.Step)("I tap", async (page) => {
31
+ const element = (0, state_1.getActiveElement)(page);
32
+ const action = await safeTap(element);
33
+ console.log(`👆 ${action === "tapped" ? "Tapped" : "Clicked"} stored element`);
34
+ });
35
+ /**
36
+ * Finds an element by selector and taps it.
37
+ * Pattern: When I tap element "#submit-btn"
38
+ */
39
+ (0, registry_1.Step)("I tap element {string}", async (page, selector) => {
40
+ const element = page.locator(selector);
41
+ const action = await safeTap(element);
42
+ console.log(`👆 ${action === "tapped" ? "Tapped" : "Clicked"} element "${selector}"`);
43
+ });
44
+ /**
45
+ * Taps at specific coordinates.
46
+ * Pattern: When I tap coordinates x:100 y:200
47
+ */
48
+ (0, registry_1.Step)("I tap coordinates x:{int} y:{int}", async (page, x, y) => {
49
+ // page.mouse.click works for both desktop and mobile viewports
50
+ await page.mouse.click(x, y);
51
+ console.log(`👆 Tapped at (${x}, ${y})`);
52
+ });
53
+ // ==================================================
54
+ // 2. VIEWPORT & EMULATION
55
+ // ==================================================
56
+ (0, registry_1.Step)("I resize window to width {int} and height {int}", async (page, width, height) => {
57
+ await page.setViewportSize({ width, height });
58
+ console.log(`📱 Resized viewport to ${width}x${height}`);
59
+ });
60
+ (0, registry_1.Step)("I simulate device {string}", async (page, deviceName) => {
61
+ const devices = {
62
+ "iPhone 12": { width: 390, height: 844 },
63
+ "iPhone SE": { width: 375, height: 667 },
64
+ iPad: { width: 768, height: 1024 },
65
+ "Pixel 5": { width: 393, height: 851 },
66
+ "Samsung Galaxy S8": { width: 360, height: 740 },
67
+ Desktop: { width: 1920, height: 1080 },
68
+ };
69
+ const size = devices[deviceName];
70
+ if (!size) {
71
+ throw new Error(`❌ Unknown device preset: "${deviceName}".`);
72
+ }
73
+ await page.setViewportSize(size);
74
+ console.log(`📱 Simulated device "${deviceName}" (${size.width}x${size.height})`);
75
+ });
76
+ // ==================================================
77
+ // 3. GEOLOCATION & PERMISSIONS
78
+ // ==================================================
79
+ (0, registry_1.Step)("I set geolocation to lat: {float} long: {float}", async (page, lat, long) => {
80
+ await page.context().setGeolocation({ latitude: lat, longitude: long });
81
+ await page.context().grantPermissions(["geolocation"]);
82
+ console.log(`🌍 Geolocation set to ${lat}, ${long}`);
83
+ });
84
+ (0, registry_1.Step)("I grant permission {string}", async (page, permission) => {
85
+ await page.context().grantPermissions([permission]);
86
+ console.log(`🛡️ Granted permission: "${permission}"`);
87
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mouse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mouse.d.ts","sourceRoot":"","sources":["../../../src/backend/actions/mouse.ts"],"names":[],"mappings":""}