laxy-verify 1.1.32 → 1.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -18
- package/dist/e2e.js +28 -2
- package/dist/verification-core/report.js +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,24 +63,6 @@ This is most useful if you ship frontend apps and want a practical gate before:
|
|
|
63
63
|
- QA handoff
|
|
64
64
|
- production release
|
|
65
65
|
|
|
66
|
-
## vs other tools
|
|
67
|
-
|
|
68
|
-
No single competitor covers this combination. Here is where each tool stops:
|
|
69
|
-
|
|
70
|
-
| | laxy-verify | LHCI | Checkly | Percy / Argos | Unlighthouse | QA Wolf |
|
|
71
|
-
|--|--|--|--|--|--|--|
|
|
72
|
-
| Build failure detection | yes | no | no | no | no | no |
|
|
73
|
-
| Auto-generated E2E | yes | no | write your own | no | no | yes |
|
|
74
|
-
| Security audit | yes | no | no | no | no | no |
|
|
75
|
-
| Lighthouse (multi-run avg) | yes | yes | no | no | yes | no |
|
|
76
|
-
| Visual diff | yes | no | no | yes | no | no |
|
|
77
|
-
| Multi-viewport checks | yes | no | separate config | no | yes | no |
|
|
78
|
-
| Ship/hold release decision | yes | score only | no | no | no | no |
|
|
79
|
-
| Zero config to start | yes | no | no | no | partial | no |
|
|
80
|
-
| Free full coverage | yes | yes | limited | limited | yes | enterprise |
|
|
81
|
-
|
|
82
|
-
LHCI gives you Lighthouse. Percy gives you visual diffs. Checkly watches your production uptime. None of them produce a merge or release decision from one command.
|
|
83
|
-
|
|
84
66
|
## The failures it is meant to catch
|
|
85
67
|
|
|
86
68
|
Use `laxy-verify` when you want to catch things like:
|
package/dist/e2e.js
CHANGED
|
@@ -82,6 +82,30 @@ function getRequiredFillTarget(selectors) {
|
|
|
82
82
|
/^textarea\[aria-required=['"]true['"]\]$/,
|
|
83
83
|
]);
|
|
84
84
|
}
|
|
85
|
+
function getFillValue(selector) {
|
|
86
|
+
const s = selector.toLowerCase();
|
|
87
|
+
if (/type=['"]email['"]|name.*email|placeholder.*email/.test(s))
|
|
88
|
+
return "test@example.com";
|
|
89
|
+
if (/type=['"]tel['"]|name.*(phone|tel)|placeholder.*(phone|tel)/.test(s))
|
|
90
|
+
return "555-0100";
|
|
91
|
+
if (/type=['"]number['"]/.test(s))
|
|
92
|
+
return "42";
|
|
93
|
+
if (/type=['"]password['"]/.test(s))
|
|
94
|
+
return "TestPass123!";
|
|
95
|
+
if (/type=['"]url['"]/.test(s))
|
|
96
|
+
return "https://example.com";
|
|
97
|
+
if (/type=['"]search['"]|name.*(query|search)|placeholder.*(search|query)/.test(s))
|
|
98
|
+
return "test query";
|
|
99
|
+
if (/name.*username|placeholder.*username/.test(s))
|
|
100
|
+
return "testuser";
|
|
101
|
+
if (/name.*name|placeholder.*name/.test(s))
|
|
102
|
+
return "Test User";
|
|
103
|
+
if (/textarea|name.*message|placeholder.*message/.test(s))
|
|
104
|
+
return "This is a test message.";
|
|
105
|
+
if (/name.*title|placeholder.*title/.test(s))
|
|
106
|
+
return "Test Title";
|
|
107
|
+
return "test input";
|
|
108
|
+
}
|
|
85
109
|
function getVerificationCoverageGaps(scenarios, tier) {
|
|
86
110
|
void tier;
|
|
87
111
|
const names = new Set(scenarios.map((scenario) => scenario.name));
|
|
@@ -117,11 +141,12 @@ function buildVerifyScenarios(snapshot, tier) {
|
|
|
117
141
|
},
|
|
118
142
|
];
|
|
119
143
|
if (fillTarget && likelyFormSurface) {
|
|
144
|
+
const fillValue = getFillValue(fillTarget);
|
|
120
145
|
const formScenario = {
|
|
121
146
|
name: "Primary form interaction",
|
|
122
147
|
steps: [
|
|
123
148
|
{ type: "check_visible", selector: fillTarget, description: "Input surface should be visible" },
|
|
124
|
-
{ type: "clear_fill", selector: fillTarget, value:
|
|
149
|
+
{ type: "clear_fill", selector: fillTarget, value: fillValue, description: `Fill a core input field with ${fillValue}` },
|
|
125
150
|
],
|
|
126
151
|
};
|
|
127
152
|
if (clickTarget) {
|
|
@@ -164,11 +189,12 @@ function buildVerifyScenarios(snapshot, tier) {
|
|
|
164
189
|
});
|
|
165
190
|
}
|
|
166
191
|
if (clickTarget && fillTarget && clickTarget !== fillTarget) {
|
|
192
|
+
const fillValue = getFillValue(fillTarget);
|
|
167
193
|
scenarios.push({
|
|
168
194
|
name: "Repeated interaction stability",
|
|
169
195
|
steps: [
|
|
170
196
|
{ type: "check_visible", selector: fillTarget, description: "Input surface should still exist" },
|
|
171
|
-
{ type: "clear_fill", selector: fillTarget, value:
|
|
197
|
+
{ type: "clear_fill", selector: fillTarget, value: fillValue, description: `Repeat the core input with ${fillValue}` },
|
|
172
198
|
{ type: "click", selector: clickTarget, description: "Trigger the CTA again" },
|
|
173
199
|
{ type: "wait", duration: 800, description: "Wait for repeated interaction response" },
|
|
174
200
|
{ type: "check_visible", selector: feedbackTarget || visibleAnchor, description: "Surface should still hold after repeat" },
|
|
@@ -29,7 +29,12 @@ function getVerificationGrade(input, thresholds = exports.DEFAULT_LH_THRESHOLDS)
|
|
|
29
29
|
input.e2eTotal > 0 &&
|
|
30
30
|
input.e2ePassed === input.e2eTotal;
|
|
31
31
|
const lighthousePassed = getLighthousePass(input.lighthouseScores, thresholds);
|
|
32
|
-
|
|
32
|
+
// Gold disqualifiers: console errors or critical security vulnerabilities
|
|
33
|
+
// mean the app has known problems — Gold should require a clean run.
|
|
34
|
+
const hasConsoleErrors = typeof input.e2eConsoleErrorCount === "number" && input.e2eConsoleErrorCount > 0;
|
|
35
|
+
const hasCriticalSecurity = !!input.securityAudit && input.securityAudit.critical > 0;
|
|
36
|
+
const goldDisqualified = hasConsoleErrors || hasCriticalSecurity;
|
|
37
|
+
if (buildPassed && e2ePassedAll && lighthousePassed && !goldDisqualified)
|
|
33
38
|
return "gold";
|
|
34
39
|
if (buildPassed && e2ePassedAll)
|
|
35
40
|
return "silver";
|