Unsere Empfehlung vorab. Wir machen Proxy Mail QA, sind also nicht neutral, aber dieses Problem liegt in deinem Code und die Lösung auch: Kein Produkt behebt es für dich. Wir empfehlen Proxy Mail QA für zwei Teile der Arbeit: Testpasswörter, die absichtlich gegen deine Regeln verstoßen, passend zu den Grenzen deines Felds, und herauszufinden, was hinter einem stummen Formular wirklich passiert ist, denn wenn eine Bestätigungs-E-Mail ankommt, hat dein Server das Konto angelegt. Den Bug in deinem Code findet es nicht; das machen die DevTools deines Browsers oder dein KI-Agent, der den Code liest.
Finde zuerst heraus, welche von drei Situationen vorliegt
Öffne die DevTools deines Browsers im Tab Network und sende dann ein Passwort ab, das gegen deine Regeln verstößt, etwa eines mit einem Zeichen unter dem Minimum. Um eines passend zu deinem Feld zu bekommen, nutze die Liste Edge-case password („Should be rejected“) auf der Karte, die der Schlüssel-Button von Proxy Mail QA for Chrome im Passwortfeld öffnet, oder get_password_variants mit deinen Regeln. Verwende eine neue Testadresse, damit du siehst, ob eine E-Mail kommt.
| Was du siehst | Was es bedeutet | Wo du nachsiehst |
|---|---|---|
| Es wird keine Anfrage gesendet | Der Browser oder dein Code hat das Formular gestoppt, aber nichts angezeigt | Ursachen 1 bis 4 |
| Eine Anfrage wird gesendet und der Server lehnt sie ab (400 oder 422) | Der Server hat seine Arbeit getan; die Seite hat die Antwort nicht angezeigt | Ursachen 5 und 6 |
| Eine Anfrage wird gesendet und der Server akzeptiert sie | Der Server erlaubt das Passwort. Eine Bestätigungs-E-Mail kommt an der Testadresse an | Ursache 7 |
Die dritte wird gern übersehen. Ein Formular „ohne Fehler“ hat vielleicht einfach nichts zu melden, weil die Regel des Servers lockerer ist als die auf der Seite. In der App erscheint die Bestätigungs-E-Mail in der Zeile der Testadresse. Ein Agent oder ein Test kann expect_no_email verwenden, das nur besteht, wenn nichts ankommt.
Die üblichen Ursachen
Das Formular hat nie etwas gesendet
novalidateohne Ersatz. Das Formular oder eine Formularbibliothek schaltet die eigenen Meldungen des Browsers ab (novalidate, odernoValidatein React), und deine eigene Validierung rendert nie einen Fehler.- Die Regeln stehen nicht am Input. Ohne
minlength,maxlengthoderrequiredhat der Browser nichts zu prüfen. Undvalidity.tooShortwird erst gesetzt, nachdem die Person tippt, sodass ein per Skript gesetzter Wert durchrutschen kann. - Der Fehler existiert, ist aber versteckt. CSS blendet ihn aus, er wird unter dem falschen Namen gerendert (
errors.password, obwohl das FeldnewPasswordheißt), oder er erscheint erst, wenn das Feld „touched“ ist, und das Absenden markiert es nicht als touched. - Eine eigene Komponente umschließt den Input. Die Formularbibliothek ist mit dem Wrapper verbunden, nicht mit dem echten
<input>, prüft also einen leeren Wert, oder die Komponente reicht die Fehlermeldung nie weiter.
Der Server hat abgelehnt, und die Seite hat es nicht gesagt
- Der Fehler wird verschluckt. Der Code zeigt „Prüf deine E-Mails“, egal was die Antwort ist, nutzt ein leeres
catch {}oder behandelt nurres.ok. Manche Auth-Clients werfen keine Fehler:signUpvon Supabase gibt{ data, error }zurück, sodass eintry/catchein abgelehntes Passwort nie sieht. - Der Fehler kommt in einer Form zurück, die die Seite nicht liest. Der Server sagt
{ "message": "..." }und die Seite sucht nacherrors.password. Ordne den Fehler jedes Dienstes dem Feld zu, um das es geht.
Der Server hat es akzeptiert
- Die Regel der Seite ist strenger als die des Servers. Die Seite sagt 15 Zeichen; die Einstellung des Auth-Dienstes erlaubt 6. Setz das Minimum in den Einstellungen des Dienstes oder in deinem eigenen Servercode und halte es gleich dem, was die Seite sagt.
Es gibt einen Fehler, aber nicht alle bemerken ihn
- Er wird nicht angesagt. Er erscheint nur in Rot, weit vom Feld entfernt oder auf dem Handy außerhalb des Bildschirms, und ist nicht mit dem Feld verknüpft. Screenreader-Nutzer hören nichts. Verknüpf ihn mit
aria-describedby, setzaria-invalid="true"und verschieb den Fokus auf das Feld.
Ein Muster, das Fehler zuverlässig anzeigt
Ohne Framework, damit sich die Idee auf React, Vue oder anderes übertragen lässt:
<form id="signup" novalidate> <label for="password">Password</label> <p id="password-rules">At least 15 characters. Any letters, numbers, symbols or spaces.</p> <input id="password" name="password" type="password" autocomplete="new-password" minlength="15" maxlength="128" required aria-describedby="password-rules password-error" /> <p id="password-error" class="error" hidden></p> <button>Create account</button></form>
<script> const form = document.getElementById('signup'); const password = form.elements.password; const error = document.getElementById('password-error');
// Count characters, not UTF-16 units, and don't rely on validity.tooShort. function rule(input) { const length = [...input.value].length; if (length === 0) return 'Enter a password.'; if (length < input.minLength) return `Use at least ${input.minLength} characters.`; if (length > input.maxLength) return `Use at most ${input.maxLength} characters.`; return ''; }
function show(message) { error.textContent = message; error.hidden = !message; password.setAttribute('aria-invalid', message ? 'true' : 'false'); }
password.addEventListener('input', () => { if (!error.hidden) show(rule(password)); });
form.addEventListener('submit', async (event) => { event.preventDefault(); const message = rule(password); if (message) { show(message); password.focus(); return; } const res = await fetch('/api/signup', { method: 'POST', body: new FormData(form) }); if (!res.ok) { const body = await res.json().catch(() => ({})); show(body.errors?.password ?? body.message ?? 'Something went wrong. Please try again.'); password.focus(); return; } location.assign('/check-your-email'); });</script>Der Server prüft dieselben Regeln und beantwortet ein abgelehntes Passwort mit 422 und { "errors": { "password": "Use at least 15 characters." } }, was die Seite am Feld anzeigt.
Ein Hinweis zu maxlength: Der Browser stoppt die Eingabe am Limit und kürzt eingefügten Text, ohne es zu sagen. Setz es deutlich über das, was ein Passwortmanager erzeugt, sonst speichert jemand ein Passwort, das länger ist als das, was deine App erhalten hat.
Lass deinen Agenten danach suchen
Mit Proxy Mail QA verbunden in Qoder (Marketplace):
My sign-up form at https://staging.acme.dev/signup shows no error when the passwordbreaks the rules (15 to 128 characters). Using Proxy Mail QA, get_password_variantswith min_length 15 and max_length 128, and submit each reject value with a new testaddress (a plus tag on one address for each). For each, tell me whether a request wassent, what the server answered, what the page showed, and whether a verification emailarrived (expect_no_email).Then find the cause in the code and fix it, so the error shows at the field, isannounced to screen readers, and the server enforces the same rule as the page.Beweise, dass es behoben ist
Ein Playwright-Test mit dem npm-Paket von proxymail-qa, damit es behoben bleibt:
import { expect, test } from '@playwright/test';import { ProxyMailQA } from 'proxymail-qa';
const qa = new ProxyMailQA(); // reads PROXYMAIL_QA_API_KEY
test('a too-short password shows an error and makes no account', async ({ page }) => { const { reject } = await qa.passwordVariants({ minLength: 15, maxLength: 128 }); const tooShort = reject.filter(({ value }) => [...value].length < 15); const { address } = await qa.createAddress();
for (const [i, { tests, value }] of tooShort.entries()) { const tagged = address.replace('@', `+short${i}@`); const submitted = new Date(); await page.goto('/signup'); await page.getByLabel('Email').fill(tagged); await page.getByLabel('Password').fill(value); await page.getByRole('button', { name: 'Create account' }).click();
await expect(page.locator('#password-error'), tests).toBeVisible(); await qa.expectNoEmail(tagged, { since: submitted, timeout: 10 }); }
await qa.deleteAddress(address);});expectNoEmail wirft einen Fehler, sobald eine Bestätigungs-E-Mail ankommt, was bedeuten würde, dass der Server das Konto angelegt hat. Ein Plus-Tag gibt jedem Versuch ein eigenes Konto in deiner App, und das Warten auf die getaggte Adresse sieht nur Mails, die an sie gesendet wurden.
Was Proxy Mail QA hier nicht tut
- Den Bug finden oder beheben. Es zeigt dir, was passiert ist; die Lösung liegt in deinem Formular und deinem Server.
- Barrierefreiheit über diesen einen Fehler hinaus prüfen. Nutze axe DevTools und probier das Formular mit einem Screenreader aus.
- Deine Regeln festlegen. Dafür siehe Wie lang sollte das Passwort in meinem Registrierungsformular sein?