cursorflow 2.7.5__py3-none-any.whl → 2.7.7__py3-none-any.whl
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.
- cursorflow/core/query_engine.py +85 -20
- cursorflow/rules/cursorflow-usage.mdc +133 -13
- {cursorflow-2.7.5.dist-info → cursorflow-2.7.7.dist-info}/METADATA +40 -2
- {cursorflow-2.7.5.dist-info → cursorflow-2.7.7.dist-info}/RECORD +8 -8
- {cursorflow-2.7.5.dist-info → cursorflow-2.7.7.dist-info}/WHEEL +0 -0
- {cursorflow-2.7.5.dist-info → cursorflow-2.7.7.dist-info}/entry_points.txt +0 -0
- {cursorflow-2.7.5.dist-info → cursorflow-2.7.7.dist-info}/licenses/LICENSE +0 -0
- {cursorflow-2.7.5.dist-info → cursorflow-2.7.7.dist-info}/top_level.txt +0 -0
cursorflow/core/query_engine.py
CHANGED
@@ -420,29 +420,90 @@ class QueryEngine:
|
|
420
420
|
|
421
421
|
# Phase 1: Enhanced DOM filtering
|
422
422
|
|
423
|
-
# Filter by selector (improved matching)
|
423
|
+
# Filter by selector (improved matching with correct field paths and priority)
|
424
424
|
if 'selector' in filters or 'select' in filters:
|
425
425
|
selector = filters.get('selector') or filters.get('select')
|
426
|
-
# Remove leading dot if present (e.g., ".class" -> "class")
|
427
|
-
selector_clean = selector.lstrip('.')
|
428
426
|
|
429
|
-
|
430
|
-
|
427
|
+
# Detect selector type
|
428
|
+
is_id_selector = selector.startswith('#')
|
429
|
+
is_class_selector = selector.startswith('.')
|
430
|
+
|
431
|
+
# Remove leading dot or hash if present (e.g., ".class" -> "class", "#id" -> "id")
|
432
|
+
selector_clean = selector.lstrip('.#')
|
433
|
+
|
434
|
+
# Determine if this looks like a simple tag name (no special characters)
|
435
|
+
is_simple_tag = selector.isalpha() and not is_id_selector and not is_class_selector
|
436
|
+
|
437
|
+
result_elements = []
|
438
|
+
for el in filtered_elements:
|
439
|
+
matched = False
|
440
|
+
|
441
|
+
# Priority 1: ID selector (#id) - only check ID field
|
442
|
+
if is_id_selector:
|
443
|
+
if selector_clean == el.get('id', ''):
|
444
|
+
result_elements.append(el)
|
445
|
+
continue
|
446
|
+
|
447
|
+
# Priority 2: Class selector (.class) - only check className
|
448
|
+
if is_class_selector:
|
449
|
+
if el.get('className'):
|
450
|
+
class_names = str(el.get('className')).split()
|
451
|
+
if selector_clean in class_names:
|
452
|
+
result_elements.append(el)
|
453
|
+
# Backward compatibility: Check classes array (old format)
|
454
|
+
elif selector_clean in el.get('classes', []):
|
455
|
+
result_elements.append(el)
|
456
|
+
continue
|
457
|
+
|
458
|
+
# Priority 3: For simple alphanumeric selectors, check tagName, ID, and className
|
459
|
+
# This handles ambiguous cases like "page" (could be tag or ID)
|
460
|
+
if is_simple_tag:
|
461
|
+
# Check tag name match (exact, case insensitive)
|
462
|
+
if selector.lower() == el.get('tagName', '').lower():
|
463
|
+
result_elements.append(el)
|
464
|
+
continue
|
465
|
+
|
466
|
+
# Check ID match (exact)
|
467
|
+
if selector_clean == el.get('id', ''):
|
468
|
+
result_elements.append(el)
|
469
|
+
continue
|
470
|
+
|
471
|
+
# Class name match (whole word match to avoid "a" matching "navbar")
|
472
|
+
if el.get('className'):
|
473
|
+
class_names = str(el.get('className')).split()
|
474
|
+
if selector_clean in class_names:
|
475
|
+
result_elements.append(el)
|
476
|
+
continue
|
477
|
+
|
478
|
+
# Backward compatibility: Check classes array (old format)
|
479
|
+
if selector_clean in el.get('classes', []):
|
480
|
+
result_elements.append(el)
|
481
|
+
|
482
|
+
# Don't fall through to selector string checks for simple tags
|
483
|
+
continue
|
484
|
+
|
485
|
+
# Priority 2: For complex selectors, check selector strings and attributes
|
431
486
|
if (
|
432
|
-
# Check
|
487
|
+
# Check selectors.unique_css (current format)
|
488
|
+
(selector in el.get('selectors', {}).get('unique_css', '')) or
|
489
|
+
# Check selectors.css (current format)
|
490
|
+
(selector in el.get('selectors', {}).get('css', '')) or
|
491
|
+
# Check selectors.xpath
|
492
|
+
(selector in el.get('selectors', {}).get('xpath', '')) or
|
493
|
+
# Check ID (exact match or contains for partial IDs)
|
494
|
+
(el.get('id') and selector_clean in str(el.get('id'))) or
|
495
|
+
# Check className (can be string or None)
|
496
|
+
(el.get('className') and selector_clean in str(el.get('className'))) or
|
497
|
+
# Backward compatibility: Check nested uniqueSelector (old format)
|
433
498
|
(selector in el.get('selectors', {}).get('uniqueSelector', '')) or
|
434
|
-
# Check top-level uniqueSelector (old format)
|
499
|
+
# Backward compatibility: Check top-level uniqueSelector (old format)
|
435
500
|
(selector in el.get('uniqueSelector', '')) or
|
436
|
-
# Check
|
437
|
-
(selector in el.get('tagName', '')) or
|
438
|
-
# Check ID
|
439
|
-
(selector == el.get('id', '')) or
|
440
|
-
# Check className string
|
441
|
-
(el.get('className') and selector_clean in el.get('className', '')) or
|
442
|
-
# Check classes array (old format)
|
501
|
+
# Backward compatibility: Check classes array (old format)
|
443
502
|
(selector_clean in el.get('classes', []))
|
444
|
-
)
|
445
|
-
|
503
|
+
):
|
504
|
+
result_elements.append(el)
|
505
|
+
|
506
|
+
filtered_elements = result_elements
|
446
507
|
|
447
508
|
# Filter by attributes
|
448
509
|
if 'with_attr' in filters:
|
@@ -460,18 +521,18 @@ class QueryEngine:
|
|
460
521
|
if el.get('accessibility', {}).get('role') == role
|
461
522
|
]
|
462
523
|
|
463
|
-
# Filter by visibility
|
524
|
+
# Filter by visibility (use correct nested path)
|
464
525
|
if 'visible' in filters and filters['visible']:
|
465
526
|
filtered_elements = [
|
466
527
|
el for el in filtered_elements
|
467
|
-
if el.get('visual_context', {}).get('
|
528
|
+
if el.get('visual_context', {}).get('visibility', {}).get('is_visible', False)
|
468
529
|
]
|
469
530
|
|
470
|
-
# Filter by interactivity
|
531
|
+
# Filter by interactivity (use correct nested path)
|
471
532
|
if 'interactive' in filters and filters['interactive']:
|
472
533
|
filtered_elements = [
|
473
534
|
el for el in filtered_elements
|
474
|
-
if el.get('accessibility', {}).get('
|
535
|
+
if el.get('accessibility', {}).get('is_interactive', False)
|
475
536
|
]
|
476
537
|
|
477
538
|
# Filter elements with errors (from console errors)
|
@@ -958,6 +1019,10 @@ class QueryEngine:
|
|
958
1019
|
elif format == "csv":
|
959
1020
|
return self._to_csv(data, data_type)
|
960
1021
|
|
1022
|
+
elif format == "dict" or format == "raw":
|
1023
|
+
# Return raw dictionary (useful for programmatic access)
|
1024
|
+
return data
|
1025
|
+
|
961
1026
|
else:
|
962
1027
|
return data
|
963
1028
|
|
@@ -963,21 +963,141 @@ 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
|
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
|
-
|
970
|
-
|
971
|
-
--
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
|
979
|
-
|
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
|
+
### **Troubleshooting Auth**
|
1080
|
+
|
1081
|
+
**Auth failing?**
|
1082
|
+
```bash
|
1083
|
+
# Inspect login form to get correct selectors
|
1084
|
+
cursorflow inspect --base-url http://localhost:3000 \
|
1085
|
+
--path /login \
|
1086
|
+
--selector "input[type='email']"
|
1087
|
+
|
1088
|
+
# Test with verbose logging
|
1089
|
+
cursorflow test --path /login \
|
1090
|
+
--save-session "test" \
|
1091
|
+
--verbose
|
1092
|
+
```
|
1093
|
+
|
1094
|
+
**Session not working?**
|
1095
|
+
```bash
|
1096
|
+
# Check saved session
|
1097
|
+
cat .cursorflow/sessions/user_session.json
|
1098
|
+
|
1099
|
+
# Force fresh login
|
1100
|
+
cursorflow test --use-session "user" --fresh-session
|
981
1101
|
```
|
982
1102
|
|
983
1103
|
## Best Practices
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: cursorflow
|
3
|
-
Version: 2.7.
|
3
|
+
Version: 2.7.7
|
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,44 @@ 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
|
+
|
181
|
+
**See:** [Complete Authentication Guide](docs/user/USAGE_GUIDE.md#authentication--session-management)
|
182
|
+
|
183
|
+
---
|
184
|
+
|
147
185
|
## 🚀 Complete Page Intelligence
|
148
186
|
|
149
187
|
Every test captures everything needed for debugging:
|
@@ -157,7 +195,7 @@ Every test captures everything needed for debugging:
|
|
157
195
|
- **Forms**: All field values at capture time (passwords masked)
|
158
196
|
- **Performance**: Load times, memory usage, reliability indicators
|
159
197
|
- **Visual**: Screenshots with comprehensive page analysis
|
160
|
-
- **Sessions**: Save/restore authenticated browser state (requires auth_config)
|
198
|
+
- **Sessions**: Save/restore authenticated browser state (requires auth_config - see Authentication below)
|
161
199
|
|
162
200
|
### **🔄 Hot Reload Intelligence**
|
163
201
|
- **Framework auto-detection** (Vite, Webpack, Next.js, Parcel, Laravel Mix)
|
@@ -26,17 +26,17 @@ cursorflow/core/log_monitor.py,sha256=pONMu_JHEnT0T62OA5KRZ4nClzKgNpifPyrfN5w_RM
|
|
26
26
|
cursorflow/core/mockup_comparator.py,sha256=ttcXdueZz9dwcUGBQ2sft4i66zRdkZkFPu41s6JlEwU,63472
|
27
27
|
cursorflow/core/output_manager.py,sha256=PT73Awq4htYVwbBN3EadXGvuy3Wreip0Y35sCg7Pz5s,28013
|
28
28
|
cursorflow/core/persistent_session.py,sha256=FsEHj4wKkycmdp6PFRHv3g333Y74yqra0x_qhUTQpik,36075
|
29
|
-
cursorflow/core/query_engine.py,sha256=
|
29
|
+
cursorflow/core/query_engine.py,sha256=lhsF0rUc86jJBYZBjx8fz5N8_BxhQhoeGgpO4w3kf00,58233
|
30
30
|
cursorflow/core/report_generator.py,sha256=-vosfyrnfVyWDbAIMlMurl90xOXqBae8d6aLd9sEqiY,10113
|
31
31
|
cursorflow/core/trace_manager.py,sha256=Jj9ultZrL1atiZXfcRVI6ynCnnfqZM-X0_taxt-llJ0,7189
|
32
32
|
cursorflow/log_sources/local_file.py,sha256=GVnhsaifIdc41twXwbxRM9-fBeRDsknDpk5IEGulnhQ,8318
|
33
33
|
cursorflow/log_sources/ssh_remote.py,sha256=_Kwh0bhRpKgq-0c98oaX2hN6h9cT-wCHlqY5NiWVCoY,8388
|
34
34
|
cursorflow/rules/__init__.py,sha256=gPcA-IkhXj03sl7cvZV0wwo7CtEkcyuKs4y0F5oQbqE,458
|
35
35
|
cursorflow/rules/cursorflow-installation.mdc,sha256=D55pzzDPAVVbE3gAtKPUGoT-2fvB-FI2l6yrTdzUIEo,10208
|
36
|
-
cursorflow/rules/cursorflow-usage.mdc,sha256=
|
37
|
-
cursorflow-2.7.
|
38
|
-
cursorflow-2.7.
|
39
|
-
cursorflow-2.7.
|
40
|
-
cursorflow-2.7.
|
41
|
-
cursorflow-2.7.
|
42
|
-
cursorflow-2.7.
|
36
|
+
cursorflow/rules/cursorflow-usage.mdc,sha256=oTp9RTyhZfRjX5DJq-R2lthT2E0nF-5gA-Ao13jjS5A,37490
|
37
|
+
cursorflow-2.7.7.dist-info/licenses/LICENSE,sha256=e4QbjAsj3bW-xgQOvQelr8sGLYDoqc48k6cKgCr_pBU,1080
|
38
|
+
cursorflow-2.7.7.dist-info/METADATA,sha256=M_sXtrzj4lW1jDIHuRnuPzrotxlv8scA78PdvRQORKg,20838
|
39
|
+
cursorflow-2.7.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
40
|
+
cursorflow-2.7.7.dist-info/entry_points.txt,sha256=-Ed_n4Uff7wClEtWS-Py6xmQabecB9f0QAOjX0w7ljA,51
|
41
|
+
cursorflow-2.7.7.dist-info/top_level.txt,sha256=t1UZwRyZP4u-ng2CEcNHmk_ZT4ibQxoihB2IjTF7ovc,11
|
42
|
+
cursorflow-2.7.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|