| 20 | 20 | | { name: "Sign up", path: "/register", expect: ["Create your account", "Create account"] }, |
| 21 | 21 | | { name: "Pricing", path: "/pricing", expect: ["Pricing"] }, |
| 22 | 22 | | { |
| 23 | | − | name: "Sign up reaches identity", |
| 23 | + | name: "Sign up refuses a bad form", |
| 24 | 24 | | path: "/register", |
| 25 | | − | // Not an address, so identity answers "Enter a valid email address." |
| 26 | | − | // before its sign-up rate limit and before any write. |
| 25 | + | // Not an address and no Turnstile answer, so nothing is written or |
| 26 | + | // counted: with Turnstile on, the site refuses it first (no person |
| 27 | + | // solved the check); with it off, identity answers "Enter a valid |
| 28 | + | // email address." before its sign-up rate limit. |
| 27 | 29 | | form: { username: "smoke-test", email: "smoke-test-not-an-address", password: "not-a-real-password" }, |
| 28 | 30 | | status: 422, |
| 29 | | − | expect: ["Enter a valid email address."], |
| 31 | + | expect: [], |
| 32 | + | expectOne: ["We could not tell that a person sent this form.", "Enter a valid email address."], |
| 30 | 33 | | }, |
| 31 | 34 | | ]; |
| 32 | 35 | | |
| ⋯ |
| 49 | 52 | | if (status !== want) return `answered ${status}, expected ${want}`; |
| 50 | 53 | | const text = pageText(html); |
| 51 | 54 | | const missing = check.expect.filter((phrase) => !text.includes(phrase)); |
| 52 | | − | return missing.length ? `missing ${missing.map((m) => JSON.stringify(m)).join(", ")}` : null; |
| 55 | + | if (missing.length) return `missing ${missing.map((m) => JSON.stringify(m)).join(", ")}`; |
| 56 | + | // `expectOne`: at least one of these phrases. |
| 57 | + | if (check.expectOne && !check.expectOne.some((phrase) => text.includes(phrase))) { |
| 58 | + | return `missing one of ${check.expectOne.map((m) => JSON.stringify(m)).join(", ")}`; |
| 59 | + | } |
| 60 | + | return null; |
| 53 | 61 | | } |
| 54 | 62 | | |
| 55 | 63 | | async function run(site) { |