cursorflow 2.7.6__tar.gz → 2.7.8__tar.gz

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 (55) hide show
  1. {cursorflow-2.7.6 → cursorflow-2.7.8}/PKG-INFO +53 -2
  2. {cursorflow-2.7.6 → cursorflow-2.7.8}/README.md +52 -1
  3. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/cli.py +152 -0
  4. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/rules/cursorflow-usage.mdc +184 -13
  5. {cursorflow-2.7.6 → cursorflow-2.7.8}/docs/user/USAGE_GUIDE.md +865 -17
  6. {cursorflow-2.7.6 → cursorflow-2.7.8}/pyproject.toml +1 -1
  7. {cursorflow-2.7.6 → cursorflow-2.7.8}/LICENSE +0 -0
  8. {cursorflow-2.7.6 → cursorflow-2.7.8}/MANIFEST.in +0 -0
  9. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/__init__.py +0 -0
  10. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/auto_init.py +0 -0
  11. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/auto_updater.py +0 -0
  12. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/action_validator.py +0 -0
  13. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/agent.py +0 -0
  14. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/auth_handler.py +0 -0
  15. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/browser_controller.py +0 -0
  16. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/browser_engine.py +0 -0
  17. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/config_validator.py +0 -0
  18. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/css_iterator.py +0 -0
  19. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/cursor_integration.py +0 -0
  20. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/cursorflow.py +0 -0
  21. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/data_presenter.py +0 -0
  22. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/error_context_collector.py +0 -0
  23. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/error_correlator.py +0 -0
  24. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/event_correlator.py +0 -0
  25. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/file_change_monitor.py +0 -0
  26. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/hmr_detector.py +0 -0
  27. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/json_utils.py +0 -0
  28. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/log_collector.py +0 -0
  29. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/log_monitor.py +0 -0
  30. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/mockup_comparator.py +0 -0
  31. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/output_manager.py +0 -0
  32. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/persistent_session.py +0 -0
  33. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/query_engine.py +0 -0
  34. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/report_generator.py +0 -0
  35. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/core/trace_manager.py +0 -0
  36. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/install_cursorflow_rules.py +0 -0
  37. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/log_sources/local_file.py +0 -0
  38. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/log_sources/ssh_remote.py +0 -0
  39. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/post_install.py +0 -0
  40. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/rules/__init__.py +0 -0
  41. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/rules/cursorflow-installation.mdc +0 -0
  42. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow/updater.py +0 -0
  43. {cursorflow-2.7.6 → cursorflow-2.7.8}/cursorflow.egg-info/SOURCES.txt +0 -0
  44. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/comprehensive_screenshot_example.py +0 -0
  45. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/element_inspection_example.py +0 -0
  46. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/element_measurement_example.py +0 -0
  47. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/enhanced_screenshot_example.py +0 -0
  48. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/hot_reload_css_iteration.py +0 -0
  49. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/mockup_comparison_example.py +0 -0
  50. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/opensas_example.py +0 -0
  51. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/react_example.py +0 -0
  52. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/responsive_testing_example.py +0 -0
  53. {cursorflow-2.7.6 → cursorflow-2.7.8}/examples/v2_comprehensive_demo.py +0 -0
  54. {cursorflow-2.7.6 → cursorflow-2.7.8}/setup.cfg +0 -0
  55. {cursorflow-2.7.6 → cursorflow-2.7.8}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cursorflow
3
- Version: 2.7.6
3
+ Version: 2.7.8
4
4
  Summary: 🔥 Complete page intelligence for AI-driven development with Hot Reload Intelligence - captures DOM, network, console, performance, HMR events, and comprehensive page analysis
5
5
  Author-email: GeekWarrior Development <rbush@cooltheory.com>
6
6
  License-Expression: MIT
@@ -144,6 +144,57 @@ cursorflow cleanup --all --dry-run
144
144
 
145
145
  ---
146
146
 
147
+ ## 🔐 Authentication & Testing Protected Pages
148
+
149
+ Test authenticated pages with automatic session management:
150
+
151
+ ```bash
152
+ # 1. Configure auth in .cursorflow/config.json
153
+ {
154
+ "base_url": "http://localhost:3000",
155
+ "auth": {
156
+ "method": "form",
157
+ "username": "test@example.com",
158
+ "password": "testpass",
159
+ "username_selector": "#email",
160
+ "password_selector": "#password",
161
+ "submit_selector": "#login-button"
162
+ }
163
+ }
164
+
165
+ # 2. Login once and save session
166
+ cursorflow test --base-url http://localhost:3000 \
167
+ --path /login \
168
+ --save-session "user"
169
+
170
+ # 3. Reuse session for protected pages (no re-login!)
171
+ cursorflow test --use-session "user" \
172
+ --path /dashboard \
173
+ --screenshot "dashboard"
174
+ ```
175
+
176
+ **Supports:**
177
+ - Form authentication (username/password)
178
+ - Cookie authentication (JWT tokens, session cookies)
179
+ - Header authentication (Bearer tokens, API keys)
180
+ - SSO authentication (Google, Microsoft, Okta, Auth0)
181
+
182
+ **SSO/OAuth Quick Start:**
183
+ ```bash
184
+ # Capture SSO auth (opens browser for manual login)
185
+ cursorflow capture-auth --base-url http://localhost:3000 \
186
+ --path /dashboard \
187
+ --output google-sso.json
188
+
189
+ # Use captured auth
190
+ # (Copy cookies from google-sso.json to .cursorflow/config.json)
191
+ cursorflow test --use-session "sso-user" --path /dashboard
192
+ ```
193
+
194
+ **See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
195
+
196
+ ---
197
+
147
198
  ## 🚀 Complete Page Intelligence
148
199
 
149
200
  Every test captures everything needed for debugging:
@@ -157,7 +208,7 @@ Every test captures everything needed for debugging:
157
208
  - **Forms**: All field values at capture time (passwords masked)
158
209
  - **Performance**: Load times, memory usage, reliability indicators
159
210
  - **Visual**: Screenshots with comprehensive page analysis
160
- - **Sessions**: Save/restore authenticated browser state (requires auth_config)
211
+ - **Sessions**: Save/restore authenticated browser state (requires auth_config - see Authentication below)
161
212
 
162
213
  ### **🔄 Hot Reload Intelligence**
163
214
  - **Framework auto-detection** (Vite, Webpack, Next.js, Parcel, Laravel Mix)
@@ -99,6 +99,57 @@ cursorflow cleanup --all --dry-run
99
99
 
100
100
  ---
101
101
 
102
+ ## 🔐 Authentication & Testing Protected Pages
103
+
104
+ Test authenticated pages with automatic session management:
105
+
106
+ ```bash
107
+ # 1. Configure auth in .cursorflow/config.json
108
+ {
109
+ "base_url": "http://localhost:3000",
110
+ "auth": {
111
+ "method": "form",
112
+ "username": "test@example.com",
113
+ "password": "testpass",
114
+ "username_selector": "#email",
115
+ "password_selector": "#password",
116
+ "submit_selector": "#login-button"
117
+ }
118
+ }
119
+
120
+ # 2. Login once and save session
121
+ cursorflow test --base-url http://localhost:3000 \
122
+ --path /login \
123
+ --save-session "user"
124
+
125
+ # 3. Reuse session for protected pages (no re-login!)
126
+ cursorflow test --use-session "user" \
127
+ --path /dashboard \
128
+ --screenshot "dashboard"
129
+ ```
130
+
131
+ **Supports:**
132
+ - Form authentication (username/password)
133
+ - Cookie authentication (JWT tokens, session cookies)
134
+ - Header authentication (Bearer tokens, API keys)
135
+ - SSO authentication (Google, Microsoft, Okta, Auth0)
136
+
137
+ **SSO/OAuth Quick Start:**
138
+ ```bash
139
+ # Capture SSO auth (opens browser for manual login)
140
+ cursorflow capture-auth --base-url http://localhost:3000 \
141
+ --path /dashboard \
142
+ --output google-sso.json
143
+
144
+ # Use captured auth
145
+ # (Copy cookies from google-sso.json to .cursorflow/config.json)
146
+ cursorflow test --use-session "sso-user" --path /dashboard
147
+ ```
148
+
149
+ **See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
150
+
151
+ ---
152
+
102
153
  ## 🚀 Complete Page Intelligence
103
154
 
104
155
  Every test captures everything needed for debugging:
@@ -112,7 +163,7 @@ Every test captures everything needed for debugging:
112
163
  - **Forms**: All field values at capture time (passwords masked)
113
164
  - **Performance**: Load times, memory usage, reliability indicators
114
165
  - **Visual**: Screenshots with comprehensive page analysis
115
- - **Sessions**: Save/restore authenticated browser state (requires auth_config)
166
+ - **Sessions**: Save/restore authenticated browser state (requires auth_config - see Authentication below)
116
167
 
117
168
  ### **🔄 Hot Reload Intelligence**
118
169
  - **Framework auto-detection** (Vite, Webpack, Next.js, Parcel, Laravel Mix)
@@ -1116,6 +1116,158 @@ def sessions(subcommand, name):
1116
1116
  else:
1117
1117
  console.print(f"[yellow]⚠️ Session not found: {name}[/yellow]")
1118
1118
 
1119
+ @main.command()
1120
+ @click.option('--base-url', '-u', required=True, help='Base URL of your application')
1121
+ @click.option('--path', '-p', default='/', help='Path to navigate to after login (e.g., /dashboard)')
1122
+ @click.option('--output', '-o', default='auth-capture.json', help='Output file for captured auth state')
1123
+ @click.option('--wait', type=int, default=60, help='Seconds to wait for manual login (default: 60)')
1124
+ def capture_auth(base_url, path, output, wait):
1125
+ """
1126
+ Capture authentication state after manual SSO/OAuth login
1127
+
1128
+ Opens a browser, waits for you to complete SSO login manually,
1129
+ then captures all cookies, localStorage, and sessionStorage.
1130
+ Perfect for Google/Microsoft/Okta SSO authentication.
1131
+
1132
+ \b
1133
+ Process:
1134
+ 1. Browser opens to your app
1135
+ 2. Complete SSO login manually (Google, Microsoft, Okta, etc.)
1136
+ 3. Navigate to a protected page (e.g., /dashboard)
1137
+ 4. CursorFlow captures all auth state
1138
+ 5. Auth state saved to JSON file
1139
+ 6. Use in .cursorflow/config.json as cookie authentication
1140
+
1141
+ \b
1142
+ Examples:
1143
+ # Capture Google SSO auth
1144
+ cursorflow capture-auth --base-url http://localhost:3000 --path /dashboard
1145
+
1146
+ # Capture with custom wait time
1147
+ cursorflow capture-auth -u http://localhost:3000 -p /dashboard --wait 120
1148
+
1149
+ # Save to custom file
1150
+ cursorflow capture-auth -u http://localhost:3000 --output google-sso.json
1151
+ """
1152
+ console.print(f"\n🔐 SSO Authentication Capture")
1153
+ console.print(f"📍 Base URL: [cyan]{base_url}[/cyan]")
1154
+ console.print(f"🎯 Target path: [cyan]{path}[/cyan]")
1155
+ console.print(f"⏱️ Wait time: [yellow]{wait}[/yellow] seconds")
1156
+ console.print(f"📄 Output file: [green]{output}[/green]\n")
1157
+
1158
+ console.print("📋 [bold]Instructions:[/bold]")
1159
+ console.print(" 1. Browser will open to your application")
1160
+ console.print(" 2. [yellow]Complete SSO login manually[/yellow] (Google, Microsoft, Okta, etc.)")
1161
+ console.print(" 3. Navigate to a protected page (e.g., /dashboard)")
1162
+ console.print(" 4. [green]Press Enter[/green] when fully logged in")
1163
+ console.print(" 5. CursorFlow will capture all auth state\n")
1164
+
1165
+ input("Press Enter to open browser and start capture...")
1166
+
1167
+ try:
1168
+ from playwright.async_api import async_playwright
1169
+ import json
1170
+
1171
+ async def capture_process():
1172
+ async with async_playwright() as p:
1173
+ # Launch browser in HEADED mode (user needs to interact)
1174
+ browser = await p.chromium.launch(headless=False)
1175
+ context = await browser.new_context()
1176
+ page = await context.new_page()
1177
+
1178
+ console.print(f"\n🌐 Opening browser to: [cyan]{base_url}[/cyan]")
1179
+ await page.goto(base_url)
1180
+
1181
+ console.print(f"\n⏳ [yellow]Complete your SSO login in the browser...[/yellow]")
1182
+ console.print(f" Waiting up to {wait} seconds...")
1183
+ console.print(f" [bold]Press Enter in this terminal when logged in and on {path}[/bold]\n")
1184
+
1185
+ # Wait for user to complete login
1186
+ import sys
1187
+ import select
1188
+
1189
+ # Simple blocking wait for Enter key
1190
+ input("Press Enter after completing login... ")
1191
+
1192
+ # Navigate to target path to ensure we're at the right place
1193
+ if path != '/':
1194
+ console.print(f"📍 Navigating to: [cyan]{path}[/cyan]")
1195
+ await page.goto(f"{base_url.rstrip('/')}{path}")
1196
+ await page.wait_for_load_state("networkidle")
1197
+
1198
+ console.print("\n📸 Capturing authentication state...")
1199
+
1200
+ # Capture all authentication data
1201
+ storage_state = await context.storage_state()
1202
+
1203
+ # Get localStorage
1204
+ local_storage = await page.evaluate("""
1205
+ () => {
1206
+ const storage = {};
1207
+ for (let i = 0; i < localStorage.length; i++) {
1208
+ const key = localStorage.key(i);
1209
+ storage[key] = localStorage.getItem(key);
1210
+ }
1211
+ return storage;
1212
+ }
1213
+ """)
1214
+
1215
+ # Get sessionStorage
1216
+ session_storage = await page.evaluate("""
1217
+ () => {
1218
+ const storage = {};
1219
+ for (let i = 0; i < sessionStorage.length; i++) {
1220
+ const key = sessionStorage.key(i);
1221
+ storage[key] = sessionStorage.getItem(key);
1222
+ }
1223
+ return storage;
1224
+ }
1225
+ """)
1226
+
1227
+ # Organize captured data
1228
+ auth_data = {
1229
+ "captured_at": time.strftime("%Y-%m-%d %H:%M:%S"),
1230
+ "base_url": base_url,
1231
+ "current_url": page.url,
1232
+ "method": "cookies",
1233
+ "cookies": storage_state.get("cookies", []),
1234
+ "localStorage": local_storage,
1235
+ "sessionStorage": session_storage,
1236
+ "usage_instructions": {
1237
+ "1": "Copy the 'cookies' array below",
1238
+ "2": "Add to .cursorflow/config.json under auth.cookies",
1239
+ "3": "Set auth.method to 'cookies'",
1240
+ "4": "Use with: cursorflow test --use-session <name>"
1241
+ }
1242
+ }
1243
+
1244
+ # Save to file
1245
+ output_path = Path(output)
1246
+ with open(output_path, 'w') as f:
1247
+ json.dump(auth_data, f, indent=2)
1248
+
1249
+ console.print(f"\n✅ Authentication state captured!")
1250
+ console.print(f"📄 Saved to: [green]{output_path.absolute()}[/green]")
1251
+ console.print(f"🍪 Captured {len(auth_data['cookies'])} cookies")
1252
+ console.print(f"💾 localStorage: {len(local_storage)} items")
1253
+ console.print(f"💾 sessionStorage: {len(session_storage)} items")
1254
+
1255
+ console.print(f"\n📋 [bold]Next steps:[/bold]")
1256
+ console.print(f" 1. Open: [cyan]{output}[/cyan]")
1257
+ console.print(f" 2. Copy the 'cookies' array")
1258
+ console.print(f" 3. Add to .cursorflow/config.json:")
1259
+ console.print(f'\n {{\n "auth": {{\n "method": "cookies",\n "cookies": [... paste here ...]\n }}\n }}\n')
1260
+ console.print(f" 4. Test with: [cyan]cursorflow test --use-session sso-user[/cyan]\n")
1261
+
1262
+ await browser.close()
1263
+
1264
+ asyncio.run(capture_process())
1265
+
1266
+ except KeyboardInterrupt:
1267
+ console.print("\n[yellow]⚠️ Capture cancelled by user[/yellow]")
1268
+ except Exception as e:
1269
+ console.print(f"[red]❌ Error capturing auth: {escape(str(e))}[/red]")
1270
+
1119
1271
  @main.command()
1120
1272
  @click.option('--base-url', '-u', required=True)
1121
1273
  @click.option('--path', '-p', default='/', help='Path to navigate to')
@@ -963,21 +963,192 @@ cursorflow test --base-url http://localhost:3000 --actions '[{"navigate": "/dash
963
963
  cursorflow test --base-url http://localhost:3000 --actions '[{"navigate": "/dashboard"}, {"screenshot": "after"}]'
964
964
  ```
965
965
 
966
- ## Authentication Testing
966
+ ## Authentication & Session Management
967
967
 
968
+ ### **Critical: Most Real Apps Need Auth**
969
+
970
+ Testing sophisticated applications requires authentication to access:
971
+ - User dashboards and protected pages
972
+ - Admin panels and settings
973
+ - Role-based features
974
+ - Shopping carts and user data
975
+ - Personalized content
976
+
977
+ ### **Three Authentication Methods**
978
+
979
+ #### **Method 1: Form Authentication (Automatic)**
980
+
981
+ Configure in `.cursorflow/config.json`:
982
+ ```json
983
+ {
984
+ "base_url": "http://localhost:3000",
985
+ "auth": {
986
+ "method": "form",
987
+ "username": "test@example.com",
988
+ "password": "testpass",
989
+ "username_selector": "#email",
990
+ "password_selector": "#password",
991
+ "submit_selector": "#login-button",
992
+ "success_indicators": ["dashboard", "profile"],
993
+ "auth_check_selectors": [".user-menu"]
994
+ }
995
+ }
996
+ ```
997
+
998
+ Then use session management:
968
999
  ```bash
969
- cursorflow test \
970
- --base-url http://localhost:3000 \
971
- --actions '[
972
- {"navigate": "/login"},
973
- {"fill": {"selector": "#username", "value": "test@example.com"}},
974
- {"fill": {"selector": "#password", "value": "testpass"}},
975
- {"click": "#login-button"},
976
- {"wait_for": ".dashboard"},
977
- {"navigate": "/protected-page"},
978
- {"wait_for": "#protected-content"},
979
- {"screenshot": "authenticated"}
980
- ]'
1000
+ # Login once, save session
1001
+ cursorflow test --base-url http://localhost:3000 \
1002
+ --path /login \
1003
+ --save-session "user"
1004
+
1005
+ # Reuse session (no re-login!)
1006
+ cursorflow test --use-session "user" \
1007
+ --path /dashboard \
1008
+ --screenshot "dashboard"
1009
+ ```
1010
+
1011
+ #### **Method 2: Cookie Authentication**
1012
+
1013
+ For JWT tokens, session cookies, or cookies from DevTools:
1014
+ ```json
1015
+ {
1016
+ "auth": {
1017
+ "method": "cookies",
1018
+ "cookies": [
1019
+ {
1020
+ "name": "session_token",
1021
+ "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
1022
+ "domain": "example.com",
1023
+ "path": "/",
1024
+ "httpOnly": true,
1025
+ "secure": true
1026
+ }
1027
+ ]
1028
+ }
1029
+ }
1030
+ ```
1031
+
1032
+ #### **Method 3: Header Authentication**
1033
+
1034
+ For API tokens and Bearer authentication:
1035
+ ```json
1036
+ {
1037
+ "auth": {
1038
+ "method": "headers",
1039
+ "headers": {
1040
+ "Authorization": "Bearer your-api-token",
1041
+ "X-API-Key": "your-api-key"
1042
+ }
1043
+ }
1044
+ }
1045
+ ```
1046
+
1047
+ ### **Session Management Benefits**
1048
+
1049
+ **Without sessions**: Re-login on every test (slow, server load)
1050
+ **With sessions**: Login once, reuse state (fast, efficient)
1051
+
1052
+ ```bash
1053
+ # Save sessions for different roles
1054
+ cursorflow test --path /login --save-session "admin"
1055
+ cursorflow test --path /login --save-session "user"
1056
+
1057
+ # Reuse as needed
1058
+ cursorflow test --use-session "admin" --path /admin/settings
1059
+ cursorflow test --use-session "user" --path /dashboard
1060
+ ```
1061
+
1062
+ ### **Manual Authentication (Complex Flows)**
1063
+
1064
+ For 2FA, OAuth, or complex flows, use explicit actions:
1065
+ ```bash
1066
+ cursorflow test --actions '[
1067
+ {"navigate": "/login"},
1068
+ {"fill": {"selector": "#email", "value": "test@example.com"}},
1069
+ {"fill": {"selector": "#password", "value": "testpass"}},
1070
+ {"click": "#login-button"},
1071
+ {"wait_for": "#otp-input"},
1072
+ {"fill": {"selector": "#otp-input", "value": "123456"}},
1073
+ {"click": "#verify-button"},
1074
+ {"wait_for": ".dashboard"},
1075
+ {"screenshot": "authenticated"}
1076
+ ]' --save-session "2fa-user"
1077
+ ```
1078
+
1079
+ ### **SSO Authentication (Google, Microsoft, Okta)**
1080
+
1081
+ **SSO requires manual capture** because of external identity providers:
1082
+
1083
+ ```bash
1084
+ # 1. Capture SSO auth (opens browser, you login manually)
1085
+ cursorflow capture-auth --base-url http://localhost:3000 \
1086
+ --path /dashboard \
1087
+ --output google-sso.json
1088
+
1089
+ # Browser opens, you complete SSO login, CursorFlow captures cookies
1090
+
1091
+ # 2. Copy cookies from google-sso.json to .cursorflow/config.json:
1092
+ {
1093
+ "auth": {
1094
+ "method": "cookies",
1095
+ "cookies": [/* paste from google-sso.json */]
1096
+ }
1097
+ }
1098
+
1099
+ # 3. Use captured auth
1100
+ cursorflow test --use-session "sso-user" --path /dashboard
1101
+ ```
1102
+
1103
+ **SSO providers supported:**
1104
+ - Google OAuth
1105
+ - Microsoft Azure AD
1106
+ - Okta
1107
+ - Auth0
1108
+ - Any OAuth/SAML provider
1109
+
1110
+ **When SSO tokens expire:**
1111
+ ```bash
1112
+ # Re-capture auth (SSO tokens typically expire in 1-24 hours)
1113
+ cursorflow capture-auth --base-url http://localhost:3000 \
1114
+ --path /dashboard \
1115
+ --output sso-refreshed.json
1116
+ ```
1117
+
1118
+ ### **Troubleshooting Auth**
1119
+
1120
+ **Auth failing?**
1121
+ ```bash
1122
+ # Inspect login form to get correct selectors
1123
+ cursorflow inspect --base-url http://localhost:3000 \
1124
+ --path /login \
1125
+ --selector "input[type='email']"
1126
+
1127
+ # Test with verbose logging
1128
+ cursorflow test --path /login \
1129
+ --save-session "test" \
1130
+ --verbose
1131
+ ```
1132
+
1133
+ **Session not working?**
1134
+ ```bash
1135
+ # Check saved session
1136
+ cat .cursorflow/sessions/user_session.json
1137
+
1138
+ # Force fresh login
1139
+ cursorflow test --use-session "user" --fresh-session
1140
+ ```
1141
+
1142
+ **SSO not working?**
1143
+ ```bash
1144
+ # Re-capture auth state
1145
+ cursorflow capture-auth --base-url http://localhost:3000 --path /dashboard
1146
+
1147
+ # Check if localStorage has tokens (some SSO stores tokens there)
1148
+ cat auth-capture.json | grep localStorage
1149
+
1150
+ # Test immediately after capture
1151
+ cursorflow test --use-session "sso-user" --path /dashboard
981
1152
  ```
982
1153
 
983
1154
  ## Best Practices