[{"data":1,"prerenderedAt":3451},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fguides\u002Fotp-magic-links\u002F":121,"\u002Fdocs\u002Fguides\u002Fotp-magic-links\u002F-surround":3446},[4,8,22,26,43,104],{"title":5,"path":6,"stem":7},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started",{"title":9,"path":10,"stem":11,"children":12,"page":21},"Setup","\u002Fdocs\u002Fsetup","1.docs\u002F2.setup",[13,17],{"title":14,"path":15,"stem":16},"Domain","\u002Fdocs\u002Fsetup\u002Fdomain","1.docs\u002F2.setup\u002F2.domain",{"title":18,"path":19,"stem":20},"Email","\u002Fdocs\u002Fsetup\u002Faccount","1.docs\u002F2.setup\u002F3.account",false,{"title":23,"path":24,"stem":25},"Email Testing API","\u002Fdocs\u002Fapi","1.docs\u002F3.api",{"title":27,"path":28,"stem":29,"children":30,"page":21},"Features","\u002Fdocs\u002Ffeatures","1.docs\u002F4.features",[31,35,39],{"title":32,"path":33,"stem":34},"Account","\u002Fdocs\u002Ffeatures\u002Faccount","1.docs\u002F4.features\u002F1.account",{"title":36,"path":37,"stem":38},"Mailbox","\u002Fdocs\u002Ffeatures\u002Fmailbox","1.docs\u002F4.features\u002F2.mailbox",{"title":40,"path":41,"stem":42},"Messages","\u002Fdocs\u002Ffeatures\u002Fmessage","1.docs\u002F4.features\u002F3.message",{"title":44,"path":45,"stem":46,"children":47,"page":21},"Guides","\u002Fdocs\u002Fguides","1.docs\u002F5.guides",[48,52,56,60,64,68,72,76,80,84,88,92,96,100],{"title":49,"path":50,"stem":51},"SMTP Test","\u002Fdocs\u002Fguides\u002Fsend-test-email","1.docs\u002F5.guides\u002F01.send-test-email",{"title":53,"path":54,"stem":55},"API Quickstart","\u002Fdocs\u002Fguides\u002Femail-testing-api","1.docs\u002F5.guides\u002F02.email-testing-api",{"title":57,"path":58,"stem":59},"CI","\u002Fdocs\u002Fguides\u002Fci","1.docs\u002F5.guides\u002F03.ci",{"title":61,"path":62,"stem":63},"Catch-All","\u002Fdocs\u002Fguides\u002Fcatch-all","1.docs\u002F5.guides\u002F04.catch-all",{"title":65,"path":66,"stem":67},"SPF, DKIM, DMARC","\u002Fdocs\u002Fguides\u002Fspf-dkim-dmarc","1.docs\u002F5.guides\u002F05.spf-dkim-dmarc",{"title":69,"path":70,"stem":71},"Playwright","\u002Fdocs\u002Fguides\u002Fe2e","1.docs\u002F5.guides\u002F06.e2e",{"title":73,"path":74,"stem":75},"Cypress","\u002Fdocs\u002Fguides\u002Fcypress","1.docs\u002F5.guides\u002F07.cypress",{"title":77,"path":78,"stem":79},"Email Clients","\u002Fdocs\u002Fguides\u002Femail-clients","1.docs\u002F5.guides\u002F08.email-clients",{"title":81,"path":82,"stem":83},"AI Agents","\u002Fdocs\u002Fguides\u002Fagents","1.docs\u002F5.guides\u002F09.agents",{"title":85,"path":86,"stem":87},"Local Development","\u002Fdocs\u002Fguides\u002Flocal-development","1.docs\u002F5.guides\u002F10.local-development",{"title":89,"path":90,"stem":91},"Size Limits","\u002Fdocs\u002Fguides\u002Femail-size-limits","1.docs\u002F5.guides\u002F11.email-size-limits",{"title":93,"path":94,"stem":95},"OTP & Magic Links","\u002Fdocs\u002Fguides\u002Fotp-magic-links","1.docs\u002F5.guides\u002F12.otp-magic-links",{"title":97,"path":98,"stem":99},"IMAP & POP3","\u002Fdocs\u002Fguides\u002Fimap-pop3","1.docs\u002F5.guides\u002F13.imap-pop3",{"title":101,"path":102,"stem":103},"Nodemailer","\u002Fdocs\u002Fguides\u002Fnodemailer","1.docs\u002F5.guides\u002F14.nodemailer",{"title":105,"path":106,"stem":107,"children":108,"page":21},"Alternatives","\u002Fdocs\u002Falternatives","1.docs\u002F6.alternatives",[109,113,117],{"title":110,"path":111,"stem":112},"Mailtrap","\u002Fdocs\u002Falternatives\u002Fmailtrap","1.docs\u002F6.alternatives\u002F1.mailtrap",{"title":114,"path":115,"stem":116},"Mailosaur","\u002Fdocs\u002Falternatives\u002Fmailosaur","1.docs\u002F6.alternatives\u002F2.mailosaur",{"title":118,"path":119,"stem":120},"Mailinator","\u002Fdocs\u002Falternatives\u002Fmailinator","1.docs\u002F6.alternatives\u002F3.mailinator",{"id":122,"title":123,"body":124,"description":3440,"extension":3441,"meta":3442,"navigation":3443,"path":94,"seo":3444,"stem":95,"__hash__":3445},"docs\u002F1.docs\u002F5.guides\u002F12.otp-magic-links.md","Testing Email OTP Codes and Magic Links",{"type":125,"value":126,"toc":3429},"minimark",[127,136,141,144,176,200,204,211,956,969,973,1837,1842,1849,1859,1869,1875,1879,2377,2392,2395,2399,2957,2960,2994,3007,3011,3014,3243,3246,3250,3330,3334,3356,3360,3425],[128,129,130,131,135],"p",{},"A one-time code (OTP) or a magic link is the one email a user can't sign in without. Most suites never read it. They pull the code from the database or stub the mailer, and the test passes while the email shows the wrong code or a link to ",[132,133,134],"code",{},"localhost",". Here the app sends the real email to the sandbox, and the test reads it the way a user would.",[137,138,140],"h2",{"id":139},"get-the-email-into-the-sandbox","Get the Email into the Sandbox",[128,142,143],{},"The route depends on who sends the email:",[145,146,147,165],"ul",{},[148,149,150,154,155,158,159,164],"li",{},[151,152,153],"strong",{},"Your app sends it."," Point its SMTP settings at ",[132,156,157],{},"send.smtp.dev"," and log in as a sandbox account (",[160,161,163],"a",{"href":162},"\u002Fdocs\u002Fguides\u002Fsend-test-email\u002F#from-your-app","settings per framework",").",[148,166,167,170,171,175],{},[151,168,169],{},"An auth provider sends it."," The code comes from the provider's servers, not your app, so changing your app's SMTP settings does nothing. Sign up with an address on a ",[160,172,174],{"href":173},"\u002Fdocs\u002Fsetup\u002Fdomain\u002F","domain whose MX points at the sandbox",", and the provider delivers there like to any other mailbox.",[128,177,178,179,182,183,187,188,191,192,195,196,199],{},"The tests below use one account, ",[132,180,181],{},"qa@test.example.com",". Every test signs up as a ",[160,184,186],{"href":185},"\u002Fdocs\u002Ffeatures\u002Faccount\u002F#plus-sign-aliasing","plus alias"," of it, such as ",[132,189,190],{},"qa+3f2a9c@test.example.com",". The alias delivers to ",[132,193,194],{},"qa@"," and stays in the message's ",[132,197,198],{},"to",", so parallel tests never read each other's codes. Plus aliases work on every plan.",[137,201,203],{"id":202},"the-mail-helper","The Mail Helper",[128,205,206,207,210],{},"A small helper next to the tests, ",[132,208,209],{},"tests\u002Fmail.ts",":",[212,213,218],"pre",{"className":214,"code":215,"language":216,"meta":217,"style":217},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const API = 'https:\u002F\u002Fapi.smtp.dev'\nconst headers = { 'X-API-KEY': process.env.SMTP_DEV_API_KEY! }\n\nasync function api(path: string) {\n  const res = await fetch(API + path, { headers })\n  if (!res.ok)\n    throw new Error(`${path} returned ${res.status}`)\n  return res.json()\n}\n\nexport async function inboxOf(address: string) {\n  const { member } = await api(`\u002Faccounts?address=${encodeURIComponent(address)}`)\n  const account = member.find((a: { address: string }) => a.address === address)\n  const { mailboxes } = await api(`\u002Faccounts\u002F${account.id}`)\n  const inbox = mailboxes.find((m: { path: string }) => m.path === 'INBOX')\n  return `\u002Faccounts\u002F${account.id}\u002Fmailboxes\u002F${inbox.id}\u002Fmessages`\n}\n\nexport async function findMessage(inbox: string, to: string, seen: string[] = []) {\n  const { member } = await api(inbox)\n  const found = member.find((m: { id: string, to: { address: string }[] }) =>\n    !seen.includes(m.id) && m.to.some(t => t.address === to))\n  return found && api(`${inbox}\u002F${found.id}`)\n}\n","ts","",[132,219,220,247,291,298,330,374,395,435,451,457,462,489,527,581,620,675,715,720,725,775,798,855,915,951],{"__ignoreMap":217},[221,222,225,229,233,237,240,244],"span",{"class":223,"line":224},"line",1,[221,226,228],{"class":227},"spNyl","const",[221,230,232],{"class":231},"sTEyZ"," API ",[221,234,236],{"class":235},"sMK4o","=",[221,238,239],{"class":235}," '",[221,241,243],{"class":242},"sfazB","https:\u002F\u002Fapi.smtp.dev",[221,245,246],{"class":235},"'\n",[221,248,250,252,255,257,260,262,266,269,271,274,277,280,282,285,288],{"class":223,"line":249},2,[221,251,228],{"class":227},[221,253,254],{"class":231}," headers ",[221,256,236],{"class":235},[221,258,259],{"class":235}," {",[221,261,239],{"class":235},[221,263,265],{"class":264},"swJcz","X-API-KEY",[221,267,268],{"class":235},"'",[221,270,210],{"class":235},[221,272,273],{"class":231}," process",[221,275,276],{"class":235},".",[221,278,279],{"class":231},"env",[221,281,276],{"class":235},[221,283,284],{"class":231},"SMTP_DEV_API_KEY",[221,286,287],{"class":235},"!",[221,289,290],{"class":235}," }\n",[221,292,294],{"class":223,"line":293},3,[221,295,297],{"emptyLinePlaceholder":296},true,"\n",[221,299,301,304,307,311,314,318,320,324,327],{"class":223,"line":300},4,[221,302,303],{"class":227},"async",[221,305,306],{"class":227}," function",[221,308,310],{"class":309},"s2Zo4"," api",[221,312,313],{"class":235},"(",[221,315,317],{"class":316},"sHdIc","path",[221,319,210],{"class":235},[221,321,323],{"class":322},"sBMFI"," string",[221,325,326],{"class":235},")",[221,328,329],{"class":235}," {\n",[221,331,333,336,339,342,346,349,351,354,357,360,363,365,368,371],{"class":223,"line":332},5,[221,334,335],{"class":227},"  const",[221,337,338],{"class":231}," res",[221,340,341],{"class":235}," =",[221,343,345],{"class":344},"s7zQu"," await",[221,347,348],{"class":309}," fetch",[221,350,313],{"class":264},[221,352,353],{"class":231},"API",[221,355,356],{"class":235}," +",[221,358,359],{"class":231}," path",[221,361,362],{"class":235},",",[221,364,259],{"class":235},[221,366,367],{"class":231}," headers",[221,369,370],{"class":235}," }",[221,372,373],{"class":264},")\n",[221,375,377,380,383,385,388,390,393],{"class":223,"line":376},6,[221,378,379],{"class":344},"  if",[221,381,382],{"class":264}," (",[221,384,287],{"class":235},[221,386,387],{"class":231},"res",[221,389,276],{"class":235},[221,391,392],{"class":231},"ok",[221,394,373],{"class":264},[221,396,398,401,404,407,409,412,414,417,420,423,425,427,430,433],{"class":223,"line":397},7,[221,399,400],{"class":344},"    throw",[221,402,403],{"class":235}," new",[221,405,406],{"class":309}," Error",[221,408,313],{"class":264},[221,410,411],{"class":235},"`${",[221,413,317],{"class":231},[221,415,416],{"class":235},"}",[221,418,419],{"class":242}," returned ",[221,421,422],{"class":235},"${",[221,424,387],{"class":231},[221,426,276],{"class":235},[221,428,429],{"class":231},"status",[221,431,432],{"class":235},"}`",[221,434,373],{"class":264},[221,436,438,441,443,445,448],{"class":223,"line":437},8,[221,439,440],{"class":344},"  return",[221,442,338],{"class":231},[221,444,276],{"class":235},[221,446,447],{"class":309},"json",[221,449,450],{"class":264},"()\n",[221,452,454],{"class":223,"line":453},9,[221,455,456],{"class":235},"}\n",[221,458,460],{"class":223,"line":459},10,[221,461,297],{"emptyLinePlaceholder":296},[221,463,465,468,471,473,476,478,481,483,485,487],{"class":223,"line":464},11,[221,466,467],{"class":344},"export",[221,469,470],{"class":227}," async",[221,472,306],{"class":227},[221,474,475],{"class":309}," inboxOf",[221,477,313],{"class":235},[221,479,480],{"class":316},"address",[221,482,210],{"class":235},[221,484,323],{"class":322},[221,486,326],{"class":235},[221,488,329],{"class":235},[221,490,492,494,496,499,501,503,505,507,509,512,515,517,520,523,525],{"class":223,"line":491},12,[221,493,335],{"class":227},[221,495,259],{"class":235},[221,497,498],{"class":231}," member",[221,500,370],{"class":235},[221,502,341],{"class":235},[221,504,345],{"class":344},[221,506,310],{"class":309},[221,508,313],{"class":264},[221,510,511],{"class":235},"`",[221,513,514],{"class":242},"\u002Faccounts?address=",[221,516,422],{"class":235},[221,518,519],{"class":309},"encodeURIComponent",[221,521,522],{"class":231},"(address)",[221,524,432],{"class":235},[221,526,373],{"class":264},[221,528,530,532,535,537,539,541,544,546,548,550,552,554,557,559,561,564,567,570,572,574,577,579],{"class":223,"line":529},13,[221,531,335],{"class":227},[221,533,534],{"class":231}," account",[221,536,341],{"class":235},[221,538,498],{"class":231},[221,540,276],{"class":235},[221,542,543],{"class":309},"find",[221,545,313],{"class":264},[221,547,313],{"class":235},[221,549,160],{"class":316},[221,551,210],{"class":235},[221,553,259],{"class":235},[221,555,556],{"class":264}," address",[221,558,210],{"class":235},[221,560,323],{"class":322},[221,562,563],{"class":235}," })",[221,565,566],{"class":227}," =>",[221,568,569],{"class":231}," a",[221,571,276],{"class":235},[221,573,480],{"class":231},[221,575,576],{"class":235}," ===",[221,578,556],{"class":231},[221,580,373],{"class":264},[221,582,584,586,588,591,593,595,597,599,601,603,606,608,611,613,616,618],{"class":223,"line":583},14,[221,585,335],{"class":227},[221,587,259],{"class":235},[221,589,590],{"class":231}," mailboxes",[221,592,370],{"class":235},[221,594,341],{"class":235},[221,596,345],{"class":344},[221,598,310],{"class":309},[221,600,313],{"class":264},[221,602,511],{"class":235},[221,604,605],{"class":242},"\u002Faccounts\u002F",[221,607,422],{"class":235},[221,609,610],{"class":231},"account",[221,612,276],{"class":235},[221,614,615],{"class":231},"id",[221,617,432],{"class":235},[221,619,373],{"class":264},[221,621,623,625,628,630,632,634,636,638,640,643,645,647,649,651,653,655,657,660,662,664,666,668,671,673],{"class":223,"line":622},15,[221,624,335],{"class":227},[221,626,627],{"class":231}," inbox",[221,629,341],{"class":235},[221,631,590],{"class":231},[221,633,276],{"class":235},[221,635,543],{"class":309},[221,637,313],{"class":264},[221,639,313],{"class":235},[221,641,642],{"class":316},"m",[221,644,210],{"class":235},[221,646,259],{"class":235},[221,648,359],{"class":264},[221,650,210],{"class":235},[221,652,323],{"class":322},[221,654,563],{"class":235},[221,656,566],{"class":227},[221,658,659],{"class":231}," m",[221,661,276],{"class":235},[221,663,317],{"class":231},[221,665,576],{"class":235},[221,667,239],{"class":235},[221,669,670],{"class":242},"INBOX",[221,672,268],{"class":235},[221,674,373],{"class":264},[221,676,678,680,683,685,687,689,691,693,695,698,700,703,705,707,709,712],{"class":223,"line":677},16,[221,679,440],{"class":344},[221,681,682],{"class":235}," `",[221,684,605],{"class":242},[221,686,422],{"class":235},[221,688,610],{"class":231},[221,690,276],{"class":235},[221,692,615],{"class":231},[221,694,416],{"class":235},[221,696,697],{"class":242},"\u002Fmailboxes\u002F",[221,699,422],{"class":235},[221,701,702],{"class":231},"inbox",[221,704,276],{"class":235},[221,706,615],{"class":231},[221,708,416],{"class":235},[221,710,711],{"class":242},"\u002Fmessages",[221,713,714],{"class":235},"`\n",[221,716,718],{"class":223,"line":717},17,[221,719,456],{"class":235},[221,721,723],{"class":223,"line":722},18,[221,724,297],{"emptyLinePlaceholder":296},[221,726,728,730,732,734,737,739,741,743,745,747,750,752,754,756,759,761,763,766,768,771,773],{"class":223,"line":727},19,[221,729,467],{"class":344},[221,731,470],{"class":227},[221,733,306],{"class":227},[221,735,736],{"class":309}," findMessage",[221,738,313],{"class":235},[221,740,702],{"class":316},[221,742,210],{"class":235},[221,744,323],{"class":322},[221,746,362],{"class":235},[221,748,749],{"class":316}," to",[221,751,210],{"class":235},[221,753,323],{"class":322},[221,755,362],{"class":235},[221,757,758],{"class":316}," seen",[221,760,210],{"class":235},[221,762,323],{"class":322},[221,764,765],{"class":231},"[] ",[221,767,236],{"class":235},[221,769,770],{"class":231}," []",[221,772,326],{"class":235},[221,774,329],{"class":235},[221,776,778,780,782,784,786,788,790,792,794,796],{"class":223,"line":777},20,[221,779,335],{"class":227},[221,781,259],{"class":235},[221,783,498],{"class":231},[221,785,370],{"class":235},[221,787,341],{"class":235},[221,789,345],{"class":344},[221,791,310],{"class":309},[221,793,313],{"class":264},[221,795,702],{"class":231},[221,797,373],{"class":264},[221,799,801,803,806,808,810,812,814,816,818,820,822,824,827,829,831,833,835,837,839,841,843,845,847,849,852],{"class":223,"line":800},21,[221,802,335],{"class":227},[221,804,805],{"class":231}," found",[221,807,341],{"class":235},[221,809,498],{"class":231},[221,811,276],{"class":235},[221,813,543],{"class":309},[221,815,313],{"class":264},[221,817,313],{"class":235},[221,819,642],{"class":316},[221,821,210],{"class":235},[221,823,259],{"class":235},[221,825,826],{"class":264}," id",[221,828,210],{"class":235},[221,830,323],{"class":322},[221,832,362],{"class":235},[221,834,749],{"class":264},[221,836,210],{"class":235},[221,838,259],{"class":235},[221,840,556],{"class":264},[221,842,210],{"class":235},[221,844,323],{"class":322},[221,846,370],{"class":235},[221,848,765],{"class":264},[221,850,851],{"class":235},"})",[221,853,854],{"class":227}," =>\n",[221,856,858,861,864,866,869,871,873,875,877,880,883,885,887,889,891,894,896,899,901,904,906,908,910,912],{"class":223,"line":857},22,[221,859,860],{"class":235},"    !",[221,862,863],{"class":231},"seen",[221,865,276],{"class":235},[221,867,868],{"class":309},"includes",[221,870,313],{"class":264},[221,872,642],{"class":231},[221,874,276],{"class":235},[221,876,615],{"class":231},[221,878,879],{"class":264},") ",[221,881,882],{"class":235},"&&",[221,884,659],{"class":231},[221,886,276],{"class":235},[221,888,198],{"class":231},[221,890,276],{"class":235},[221,892,893],{"class":309},"some",[221,895,313],{"class":264},[221,897,898],{"class":316},"t",[221,900,566],{"class":227},[221,902,903],{"class":231}," t",[221,905,276],{"class":235},[221,907,480],{"class":231},[221,909,576],{"class":235},[221,911,749],{"class":231},[221,913,914],{"class":264},"))\n",[221,916,918,920,922,925,927,929,931,933,935,938,940,943,945,947,949],{"class":223,"line":917},23,[221,919,440],{"class":344},[221,921,805],{"class":231},[221,923,924],{"class":235}," &&",[221,926,310],{"class":309},[221,928,313],{"class":264},[221,930,411],{"class":235},[221,932,702],{"class":231},[221,934,416],{"class":235},[221,936,937],{"class":242},"\u002F",[221,939,422],{"class":235},[221,941,942],{"class":231},"found",[221,944,276],{"class":235},[221,946,615],{"class":231},[221,948,432],{"class":235},[221,950,373],{"class":264},[221,952,954],{"class":223,"line":953},24,[221,955,456],{"class":235},[128,957,958,961,962,965,966,968],{},[132,959,960],{},"findMessage"," returns the newest message sent to an address, or ",[132,963,964],{},"undefined"," while there is none. ",[132,967,863],{}," lists message ids to skip, which is how a test waits for the second email after a resend.",[137,970,972],{"id":971},"reading-a-one-time-code","Reading a One-Time Code",[212,974,976],{"className":214,"code":975,"language":216,"meta":217,"style":217},"import { expect, test } from '@playwright\u002Ftest'\nimport { findMessage, inboxOf } from '.\u002Fmail'\n\nlet inbox: string\ntest.beforeAll(async () => {\n  inbox = await inboxOf('qa@test.example.com')\n})\n\nconst newAddress = () => `qa+${crypto.randomUUID()}@test.example.com`\nconst codeIn = (text: string) => text.match(\u002Fverification code is\\s*((?:\\d\\s*){6})\u002F)?.[1]?.replace(\u002F\\s\u002Fg, '')\n\nasync function nextMessage(to: string, seen: string[] = []) {\n  await expect.poll(() => findMessage(inbox, to, seen), { timeout: 30_000 }).toBeTruthy()\n  return findMessage(inbox, to, seen)\n}\n\ntest('signup with an emailed code', async ({ page }) => {\n  const address = newAddress()\n\n  await page.goto('\u002Fsignup')\n  await page.getByLabel('Email').fill(address)\n  await page.getByRole('button', { name: 'Create account' }).click()\n\n  const message = await nextMessage(address)\n  const code = codeIn(message.text)\n  expect(code).toBeDefined()\n\n  const mail = await page.context().newPage()\n  await mail.setContent(message.html.join(''))\n  expect(codeIn(await mail.locator('body').textContent() ?? '')).toBe(code)\n  await mail.close()\n\n  await page.getByLabel('Code').fill(code!)\n  await page.getByRole('button', { name: 'Verify' }).click()\n  await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible()\n})\n",[132,977,978,1005,1028,1032,1044,1065,1086,1092,1096,1134,1219,1223,1258,1315,1335,1339,1343,1372,1385,1389,1411,1443,1490,1494,1513,1537,1556,1561,1589,1622,1682,1696,1701,1735,1779,1830],{"__ignoreMap":217},[221,979,980,983,985,988,990,993,995,998,1000,1003],{"class":223,"line":224},[221,981,982],{"class":344},"import",[221,984,259],{"class":235},[221,986,987],{"class":231}," expect",[221,989,362],{"class":235},[221,991,992],{"class":231}," test",[221,994,370],{"class":235},[221,996,997],{"class":344}," from",[221,999,239],{"class":235},[221,1001,1002],{"class":242},"@playwright\u002Ftest",[221,1004,246],{"class":235},[221,1006,1007,1009,1011,1013,1015,1017,1019,1021,1023,1026],{"class":223,"line":249},[221,1008,982],{"class":344},[221,1010,259],{"class":235},[221,1012,736],{"class":231},[221,1014,362],{"class":235},[221,1016,475],{"class":231},[221,1018,370],{"class":235},[221,1020,997],{"class":344},[221,1022,239],{"class":235},[221,1024,1025],{"class":242},".\u002Fmail",[221,1027,246],{"class":235},[221,1029,1030],{"class":223,"line":293},[221,1031,297],{"emptyLinePlaceholder":296},[221,1033,1034,1037,1039,1041],{"class":223,"line":300},[221,1035,1036],{"class":227},"let",[221,1038,627],{"class":231},[221,1040,210],{"class":235},[221,1042,1043],{"class":322}," string\n",[221,1045,1046,1049,1051,1054,1056,1058,1061,1063],{"class":223,"line":332},[221,1047,1048],{"class":231},"test",[221,1050,276],{"class":235},[221,1052,1053],{"class":309},"beforeAll",[221,1055,313],{"class":231},[221,1057,303],{"class":227},[221,1059,1060],{"class":235}," ()",[221,1062,566],{"class":227},[221,1064,329],{"class":235},[221,1066,1067,1070,1072,1074,1076,1078,1080,1082,1084],{"class":223,"line":376},[221,1068,1069],{"class":231},"  inbox",[221,1071,341],{"class":235},[221,1073,345],{"class":344},[221,1075,475],{"class":309},[221,1077,313],{"class":264},[221,1079,268],{"class":235},[221,1081,181],{"class":242},[221,1083,268],{"class":235},[221,1085,373],{"class":264},[221,1087,1088,1090],{"class":223,"line":397},[221,1089,416],{"class":235},[221,1091,373],{"class":231},[221,1093,1094],{"class":223,"line":437},[221,1095,297],{"emptyLinePlaceholder":296},[221,1097,1098,1100,1103,1105,1107,1109,1111,1114,1116,1119,1121,1124,1127,1129,1132],{"class":223,"line":453},[221,1099,228],{"class":227},[221,1101,1102],{"class":231}," newAddress ",[221,1104,236],{"class":235},[221,1106,1060],{"class":235},[221,1108,566],{"class":227},[221,1110,682],{"class":235},[221,1112,1113],{"class":242},"qa+",[221,1115,422],{"class":235},[221,1117,1118],{"class":231},"crypto",[221,1120,276],{"class":235},[221,1122,1123],{"class":309},"randomUUID",[221,1125,1126],{"class":231},"()",[221,1128,416],{"class":235},[221,1130,1131],{"class":242},"@test.example.com",[221,1133,714],{"class":235},[221,1135,1136,1138,1141,1143,1145,1148,1150,1152,1154,1156,1159,1161,1164,1166,1168,1171,1174,1177,1180,1182,1185,1188,1192,1195,1197,1200,1202,1204,1207,1209,1212,1214,1217],{"class":223,"line":459},[221,1137,228],{"class":227},[221,1139,1140],{"class":231}," codeIn ",[221,1142,236],{"class":235},[221,1144,382],{"class":235},[221,1146,1147],{"class":316},"text",[221,1149,210],{"class":235},[221,1151,323],{"class":322},[221,1153,326],{"class":235},[221,1155,566],{"class":227},[221,1157,1158],{"class":231}," text",[221,1160,276],{"class":235},[221,1162,1163],{"class":309},"match",[221,1165,313],{"class":231},[221,1167,937],{"class":235},[221,1169,1170],{"class":242},"verification code is\\s",[221,1172,1173],{"class":235},"*((?:",[221,1175,1176],{"class":242},"\\d\\s",[221,1178,1179],{"class":235},"*){6})\u002F",[221,1181,326],{"class":231},[221,1183,1184],{"class":235},"?.",[221,1186,1187],{"class":231},"[",[221,1189,1191],{"class":1190},"sbssI","1",[221,1193,1194],{"class":231},"]",[221,1196,1184],{"class":235},[221,1198,1199],{"class":309},"replace",[221,1201,313],{"class":231},[221,1203,937],{"class":235},[221,1205,1206],{"class":242},"\\s",[221,1208,937],{"class":235},[221,1210,1211],{"class":1190},"g",[221,1213,362],{"class":235},[221,1215,1216],{"class":235}," ''",[221,1218,373],{"class":231},[221,1220,1221],{"class":223,"line":464},[221,1222,297],{"emptyLinePlaceholder":296},[221,1224,1225,1227,1229,1232,1234,1236,1238,1240,1242,1244,1246,1248,1250,1252,1254,1256],{"class":223,"line":491},[221,1226,303],{"class":227},[221,1228,306],{"class":227},[221,1230,1231],{"class":309}," nextMessage",[221,1233,313],{"class":235},[221,1235,198],{"class":316},[221,1237,210],{"class":235},[221,1239,323],{"class":322},[221,1241,362],{"class":235},[221,1243,758],{"class":316},[221,1245,210],{"class":235},[221,1247,323],{"class":322},[221,1249,765],{"class":231},[221,1251,236],{"class":235},[221,1253,770],{"class":231},[221,1255,326],{"class":235},[221,1257,329],{"class":235},[221,1259,1260,1263,1265,1267,1270,1272,1274,1276,1278,1280,1282,1284,1286,1288,1290,1292,1294,1296,1299,1301,1304,1306,1308,1310,1313],{"class":223,"line":529},[221,1261,1262],{"class":344},"  await",[221,1264,987],{"class":231},[221,1266,276],{"class":235},[221,1268,1269],{"class":309},"poll",[221,1271,313],{"class":264},[221,1273,1126],{"class":235},[221,1275,566],{"class":227},[221,1277,736],{"class":309},[221,1279,313],{"class":264},[221,1281,702],{"class":231},[221,1283,362],{"class":235},[221,1285,749],{"class":231},[221,1287,362],{"class":235},[221,1289,758],{"class":231},[221,1291,326],{"class":264},[221,1293,362],{"class":235},[221,1295,259],{"class":235},[221,1297,1298],{"class":264}," timeout",[221,1300,210],{"class":235},[221,1302,1303],{"class":1190}," 30_000",[221,1305,370],{"class":235},[221,1307,326],{"class":264},[221,1309,276],{"class":235},[221,1311,1312],{"class":309},"toBeTruthy",[221,1314,450],{"class":264},[221,1316,1317,1319,1321,1323,1325,1327,1329,1331,1333],{"class":223,"line":583},[221,1318,440],{"class":344},[221,1320,736],{"class":309},[221,1322,313],{"class":264},[221,1324,702],{"class":231},[221,1326,362],{"class":235},[221,1328,749],{"class":231},[221,1330,362],{"class":235},[221,1332,758],{"class":231},[221,1334,373],{"class":264},[221,1336,1337],{"class":223,"line":622},[221,1338,456],{"class":235},[221,1340,1341],{"class":223,"line":677},[221,1342,297],{"emptyLinePlaceholder":296},[221,1344,1345,1347,1349,1351,1354,1356,1358,1360,1363,1366,1368,1370],{"class":223,"line":717},[221,1346,1048],{"class":309},[221,1348,313],{"class":231},[221,1350,268],{"class":235},[221,1352,1353],{"class":242},"signup with an emailed code",[221,1355,268],{"class":235},[221,1357,362],{"class":235},[221,1359,470],{"class":227},[221,1361,1362],{"class":235}," ({",[221,1364,1365],{"class":316}," page",[221,1367,563],{"class":235},[221,1369,566],{"class":227},[221,1371,329],{"class":235},[221,1373,1374,1376,1378,1380,1383],{"class":223,"line":722},[221,1375,335],{"class":227},[221,1377,556],{"class":231},[221,1379,341],{"class":235},[221,1381,1382],{"class":309}," newAddress",[221,1384,450],{"class":264},[221,1386,1387],{"class":223,"line":727},[221,1388,297],{"emptyLinePlaceholder":296},[221,1390,1391,1393,1395,1397,1400,1402,1404,1407,1409],{"class":223,"line":777},[221,1392,1262],{"class":344},[221,1394,1365],{"class":231},[221,1396,276],{"class":235},[221,1398,1399],{"class":309},"goto",[221,1401,313],{"class":264},[221,1403,268],{"class":235},[221,1405,1406],{"class":242},"\u002Fsignup",[221,1408,268],{"class":235},[221,1410,373],{"class":264},[221,1412,1413,1415,1417,1419,1422,1424,1426,1428,1430,1432,1434,1437,1439,1441],{"class":223,"line":800},[221,1414,1262],{"class":344},[221,1416,1365],{"class":231},[221,1418,276],{"class":235},[221,1420,1421],{"class":309},"getByLabel",[221,1423,313],{"class":264},[221,1425,268],{"class":235},[221,1427,18],{"class":242},[221,1429,268],{"class":235},[221,1431,326],{"class":264},[221,1433,276],{"class":235},[221,1435,1436],{"class":309},"fill",[221,1438,313],{"class":264},[221,1440,480],{"class":231},[221,1442,373],{"class":264},[221,1444,1445,1447,1449,1451,1454,1456,1458,1461,1463,1465,1467,1470,1472,1474,1477,1479,1481,1483,1485,1488],{"class":223,"line":857},[221,1446,1262],{"class":344},[221,1448,1365],{"class":231},[221,1450,276],{"class":235},[221,1452,1453],{"class":309},"getByRole",[221,1455,313],{"class":264},[221,1457,268],{"class":235},[221,1459,1460],{"class":242},"button",[221,1462,268],{"class":235},[221,1464,362],{"class":235},[221,1466,259],{"class":235},[221,1468,1469],{"class":264}," name",[221,1471,210],{"class":235},[221,1473,239],{"class":235},[221,1475,1476],{"class":242},"Create account",[221,1478,268],{"class":235},[221,1480,370],{"class":235},[221,1482,326],{"class":264},[221,1484,276],{"class":235},[221,1486,1487],{"class":309},"click",[221,1489,450],{"class":264},[221,1491,1492],{"class":223,"line":917},[221,1493,297],{"emptyLinePlaceholder":296},[221,1495,1496,1498,1501,1503,1505,1507,1509,1511],{"class":223,"line":953},[221,1497,335],{"class":227},[221,1499,1500],{"class":231}," message",[221,1502,341],{"class":235},[221,1504,345],{"class":344},[221,1506,1231],{"class":309},[221,1508,313],{"class":264},[221,1510,480],{"class":231},[221,1512,373],{"class":264},[221,1514,1516,1518,1521,1523,1526,1528,1531,1533,1535],{"class":223,"line":1515},25,[221,1517,335],{"class":227},[221,1519,1520],{"class":231}," code",[221,1522,341],{"class":235},[221,1524,1525],{"class":309}," codeIn",[221,1527,313],{"class":264},[221,1529,1530],{"class":231},"message",[221,1532,276],{"class":235},[221,1534,1147],{"class":231},[221,1536,373],{"class":264},[221,1538,1540,1543,1545,1547,1549,1551,1554],{"class":223,"line":1539},26,[221,1541,1542],{"class":309},"  expect",[221,1544,313],{"class":264},[221,1546,132],{"class":231},[221,1548,326],{"class":264},[221,1550,276],{"class":235},[221,1552,1553],{"class":309},"toBeDefined",[221,1555,450],{"class":264},[221,1557,1559],{"class":223,"line":1558},27,[221,1560,297],{"emptyLinePlaceholder":296},[221,1562,1564,1566,1569,1571,1573,1575,1577,1580,1582,1584,1587],{"class":223,"line":1563},28,[221,1565,335],{"class":227},[221,1567,1568],{"class":231}," mail",[221,1570,341],{"class":235},[221,1572,345],{"class":344},[221,1574,1365],{"class":231},[221,1576,276],{"class":235},[221,1578,1579],{"class":309},"context",[221,1581,1126],{"class":264},[221,1583,276],{"class":235},[221,1585,1586],{"class":309},"newPage",[221,1588,450],{"class":264},[221,1590,1592,1594,1596,1598,1601,1603,1605,1607,1610,1612,1615,1617,1620],{"class":223,"line":1591},29,[221,1593,1262],{"class":344},[221,1595,1568],{"class":231},[221,1597,276],{"class":235},[221,1599,1600],{"class":309},"setContent",[221,1602,313],{"class":264},[221,1604,1530],{"class":231},[221,1606,276],{"class":235},[221,1608,1609],{"class":231},"html",[221,1611,276],{"class":235},[221,1613,1614],{"class":309},"join",[221,1616,313],{"class":264},[221,1618,1619],{"class":235},"''",[221,1621,914],{"class":264},[221,1623,1625,1627,1629,1632,1634,1637,1639,1641,1644,1646,1648,1651,1653,1655,1657,1660,1663,1666,1668,1671,1673,1676,1678,1680],{"class":223,"line":1624},30,[221,1626,1542],{"class":309},[221,1628,313],{"class":264},[221,1630,1631],{"class":309},"codeIn",[221,1633,313],{"class":264},[221,1635,1636],{"class":344},"await",[221,1638,1568],{"class":231},[221,1640,276],{"class":235},[221,1642,1643],{"class":309},"locator",[221,1645,313],{"class":264},[221,1647,268],{"class":235},[221,1649,1650],{"class":242},"body",[221,1652,268],{"class":235},[221,1654,326],{"class":264},[221,1656,276],{"class":235},[221,1658,1659],{"class":309},"textContent",[221,1661,1662],{"class":264},"() ",[221,1664,1665],{"class":235},"??",[221,1667,1216],{"class":235},[221,1669,1670],{"class":264},"))",[221,1672,276],{"class":235},[221,1674,1675],{"class":309},"toBe",[221,1677,313],{"class":264},[221,1679,132],{"class":231},[221,1681,373],{"class":264},[221,1683,1685,1687,1689,1691,1694],{"class":223,"line":1684},31,[221,1686,1262],{"class":344},[221,1688,1568],{"class":231},[221,1690,276],{"class":235},[221,1692,1693],{"class":309},"close",[221,1695,450],{"class":264},[221,1697,1699],{"class":223,"line":1698},32,[221,1700,297],{"emptyLinePlaceholder":296},[221,1702,1704,1706,1708,1710,1712,1714,1716,1719,1721,1723,1725,1727,1729,1731,1733],{"class":223,"line":1703},33,[221,1705,1262],{"class":344},[221,1707,1365],{"class":231},[221,1709,276],{"class":235},[221,1711,1421],{"class":309},[221,1713,313],{"class":264},[221,1715,268],{"class":235},[221,1717,1718],{"class":242},"Code",[221,1720,268],{"class":235},[221,1722,326],{"class":264},[221,1724,276],{"class":235},[221,1726,1436],{"class":309},[221,1728,313],{"class":264},[221,1730,132],{"class":231},[221,1732,287],{"class":235},[221,1734,373],{"class":264},[221,1736,1738,1740,1742,1744,1746,1748,1750,1752,1754,1756,1758,1760,1762,1764,1767,1769,1771,1773,1775,1777],{"class":223,"line":1737},34,[221,1739,1262],{"class":344},[221,1741,1365],{"class":231},[221,1743,276],{"class":235},[221,1745,1453],{"class":309},[221,1747,313],{"class":264},[221,1749,268],{"class":235},[221,1751,1460],{"class":242},[221,1753,268],{"class":235},[221,1755,362],{"class":235},[221,1757,259],{"class":235},[221,1759,1469],{"class":264},[221,1761,210],{"class":235},[221,1763,239],{"class":235},[221,1765,1766],{"class":242},"Verify",[221,1768,268],{"class":235},[221,1770,370],{"class":235},[221,1772,326],{"class":264},[221,1774,276],{"class":235},[221,1776,1487],{"class":309},[221,1778,450],{"class":264},[221,1780,1782,1784,1786,1788,1791,1793,1795,1797,1799,1802,1804,1806,1808,1810,1812,1814,1817,1819,1821,1823,1825,1828],{"class":223,"line":1781},35,[221,1783,1262],{"class":344},[221,1785,987],{"class":309},[221,1787,313],{"class":264},[221,1789,1790],{"class":231},"page",[221,1792,276],{"class":235},[221,1794,1453],{"class":309},[221,1796,313],{"class":264},[221,1798,268],{"class":235},[221,1800,1801],{"class":242},"heading",[221,1803,268],{"class":235},[221,1805,362],{"class":235},[221,1807,259],{"class":235},[221,1809,1469],{"class":264},[221,1811,210],{"class":235},[221,1813,239],{"class":235},[221,1815,1816],{"class":242},"Welcome",[221,1818,268],{"class":235},[221,1820,370],{"class":235},[221,1822,1670],{"class":264},[221,1824,276],{"class":235},[221,1826,1827],{"class":309},"toBeVisible",[221,1829,450],{"class":264},[221,1831,1833,1835],{"class":223,"line":1832},36,[221,1834,416],{"class":235},[221,1836,373],{"class":231},[128,1838,1839,1841],{},[132,1840,1631],{}," matches the sentence the template writes, not any six digits. Take this email:",[212,1843,1847],{"className":1844,"code":1846,"language":1147,"meta":217},[1845],"language-text","Acme account 739201\n\nYour verification code is 482913.\nIt expires in 10 minutes.\n",[132,1848,1846],{"__ignoreMap":217},[128,1850,1851,1854,1855,1858],{},[132,1852,1853],{},"\u002F\\b\\d{6}\\b\u002F"," returns ",[132,1856,1857],{},"739201",". A loose pattern also picks up an order number, a street address, or an id inside a tracking link, whichever comes first.",[128,1860,1861,1862,1864,1865,1868],{},"The HTML part often draws each digit in its own styled element, so the markup holds no six-digit run at all. The test renders the HTML in a second page and reads the code from the page's text with the same ",[132,1863,1631],{},", which catches two templates that have drifted apart. The pattern allows whitespace after each digit because that text reads ",[132,1866,1867],{},"4 8 2 9 1 3"," when the template puts each element on its own line.",[128,1870,1871,1872,276],{},"When an email has no text part, read the code from that page instead: ",[132,1873,1874],{},"codeIn(await mail.locator('body').textContent() ?? '')",[137,1876,1878],{"id":1877},"testing-a-resent-code","Testing a Resent Code",[212,1880,1882],{"className":214,"code":1881,"language":216,"meta":217,"style":217},"test('a resent code replaces the first one', async ({ page }) => {\n  const address = newAddress()\n\n  await page.goto('\u002Fsignup')\n  await page.getByLabel('Email').fill(address)\n  await page.getByRole('button', { name: 'Create account' }).click()\n  const first = await nextMessage(address)\n\n  await page.getByRole('button', { name: 'Resend code' }).click()\n  const second = await nextMessage(address, [first.id])\n\n  await page.getByLabel('Code').fill(codeIn(first.text)!)\n  await page.getByRole('button', { name: 'Verify' }).click()\n  await expect(page.getByRole('alert')).toBeVisible()\n\n  await page.getByLabel('Code').fill(codeIn(second.text)!)\n  await page.getByRole('button', { name: 'Verify' }).click()\n  await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible()\n})\n",[132,1883,1884,1911,1923,1927,1947,1977,2019,2038,2042,2085,2117,2121,2163,2205,2236,2240,2283,2325,2371],{"__ignoreMap":217},[221,1885,1886,1888,1890,1892,1895,1897,1899,1901,1903,1905,1907,1909],{"class":223,"line":224},[221,1887,1048],{"class":309},[221,1889,313],{"class":231},[221,1891,268],{"class":235},[221,1893,1894],{"class":242},"a resent code replaces the first one",[221,1896,268],{"class":235},[221,1898,362],{"class":235},[221,1900,470],{"class":227},[221,1902,1362],{"class":235},[221,1904,1365],{"class":316},[221,1906,563],{"class":235},[221,1908,566],{"class":227},[221,1910,329],{"class":235},[221,1912,1913,1915,1917,1919,1921],{"class":223,"line":249},[221,1914,335],{"class":227},[221,1916,556],{"class":231},[221,1918,341],{"class":235},[221,1920,1382],{"class":309},[221,1922,450],{"class":264},[221,1924,1925],{"class":223,"line":293},[221,1926,297],{"emptyLinePlaceholder":296},[221,1928,1929,1931,1933,1935,1937,1939,1941,1943,1945],{"class":223,"line":300},[221,1930,1262],{"class":344},[221,1932,1365],{"class":231},[221,1934,276],{"class":235},[221,1936,1399],{"class":309},[221,1938,313],{"class":264},[221,1940,268],{"class":235},[221,1942,1406],{"class":242},[221,1944,268],{"class":235},[221,1946,373],{"class":264},[221,1948,1949,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973,1975],{"class":223,"line":332},[221,1950,1262],{"class":344},[221,1952,1365],{"class":231},[221,1954,276],{"class":235},[221,1956,1421],{"class":309},[221,1958,313],{"class":264},[221,1960,268],{"class":235},[221,1962,18],{"class":242},[221,1964,268],{"class":235},[221,1966,326],{"class":264},[221,1968,276],{"class":235},[221,1970,1436],{"class":309},[221,1972,313],{"class":264},[221,1974,480],{"class":231},[221,1976,373],{"class":264},[221,1978,1979,1981,1983,1985,1987,1989,1991,1993,1995,1997,1999,2001,2003,2005,2007,2009,2011,2013,2015,2017],{"class":223,"line":376},[221,1980,1262],{"class":344},[221,1982,1365],{"class":231},[221,1984,276],{"class":235},[221,1986,1453],{"class":309},[221,1988,313],{"class":264},[221,1990,268],{"class":235},[221,1992,1460],{"class":242},[221,1994,268],{"class":235},[221,1996,362],{"class":235},[221,1998,259],{"class":235},[221,2000,1469],{"class":264},[221,2002,210],{"class":235},[221,2004,239],{"class":235},[221,2006,1476],{"class":242},[221,2008,268],{"class":235},[221,2010,370],{"class":235},[221,2012,326],{"class":264},[221,2014,276],{"class":235},[221,2016,1487],{"class":309},[221,2018,450],{"class":264},[221,2020,2021,2023,2026,2028,2030,2032,2034,2036],{"class":223,"line":397},[221,2022,335],{"class":227},[221,2024,2025],{"class":231}," first",[221,2027,341],{"class":235},[221,2029,345],{"class":344},[221,2031,1231],{"class":309},[221,2033,313],{"class":264},[221,2035,480],{"class":231},[221,2037,373],{"class":264},[221,2039,2040],{"class":223,"line":437},[221,2041,297],{"emptyLinePlaceholder":296},[221,2043,2044,2046,2048,2050,2052,2054,2056,2058,2060,2062,2064,2066,2068,2070,2073,2075,2077,2079,2081,2083],{"class":223,"line":453},[221,2045,1262],{"class":344},[221,2047,1365],{"class":231},[221,2049,276],{"class":235},[221,2051,1453],{"class":309},[221,2053,313],{"class":264},[221,2055,268],{"class":235},[221,2057,1460],{"class":242},[221,2059,268],{"class":235},[221,2061,362],{"class":235},[221,2063,259],{"class":235},[221,2065,1469],{"class":264},[221,2067,210],{"class":235},[221,2069,239],{"class":235},[221,2071,2072],{"class":242},"Resend code",[221,2074,268],{"class":235},[221,2076,370],{"class":235},[221,2078,326],{"class":264},[221,2080,276],{"class":235},[221,2082,1487],{"class":309},[221,2084,450],{"class":264},[221,2086,2087,2089,2092,2094,2096,2098,2100,2102,2104,2107,2110,2112,2114],{"class":223,"line":459},[221,2088,335],{"class":227},[221,2090,2091],{"class":231}," second",[221,2093,341],{"class":235},[221,2095,345],{"class":344},[221,2097,1231],{"class":309},[221,2099,313],{"class":264},[221,2101,480],{"class":231},[221,2103,362],{"class":235},[221,2105,2106],{"class":264}," [",[221,2108,2109],{"class":231},"first",[221,2111,276],{"class":235},[221,2113,615],{"class":231},[221,2115,2116],{"class":264},"])\n",[221,2118,2119],{"class":223,"line":464},[221,2120,297],{"emptyLinePlaceholder":296},[221,2122,2123,2125,2127,2129,2131,2133,2135,2137,2139,2141,2143,2145,2147,2149,2151,2153,2155,2157,2159,2161],{"class":223,"line":491},[221,2124,1262],{"class":344},[221,2126,1365],{"class":231},[221,2128,276],{"class":235},[221,2130,1421],{"class":309},[221,2132,313],{"class":264},[221,2134,268],{"class":235},[221,2136,1718],{"class":242},[221,2138,268],{"class":235},[221,2140,326],{"class":264},[221,2142,276],{"class":235},[221,2144,1436],{"class":309},[221,2146,313],{"class":264},[221,2148,1631],{"class":309},[221,2150,313],{"class":264},[221,2152,2109],{"class":231},[221,2154,276],{"class":235},[221,2156,1147],{"class":231},[221,2158,326],{"class":264},[221,2160,287],{"class":235},[221,2162,373],{"class":264},[221,2164,2165,2167,2169,2171,2173,2175,2177,2179,2181,2183,2185,2187,2189,2191,2193,2195,2197,2199,2201,2203],{"class":223,"line":529},[221,2166,1262],{"class":344},[221,2168,1365],{"class":231},[221,2170,276],{"class":235},[221,2172,1453],{"class":309},[221,2174,313],{"class":264},[221,2176,268],{"class":235},[221,2178,1460],{"class":242},[221,2180,268],{"class":235},[221,2182,362],{"class":235},[221,2184,259],{"class":235},[221,2186,1469],{"class":264},[221,2188,210],{"class":235},[221,2190,239],{"class":235},[221,2192,1766],{"class":242},[221,2194,268],{"class":235},[221,2196,370],{"class":235},[221,2198,326],{"class":264},[221,2200,276],{"class":235},[221,2202,1487],{"class":309},[221,2204,450],{"class":264},[221,2206,2207,2209,2211,2213,2215,2217,2219,2221,2223,2226,2228,2230,2232,2234],{"class":223,"line":583},[221,2208,1262],{"class":344},[221,2210,987],{"class":309},[221,2212,313],{"class":264},[221,2214,1790],{"class":231},[221,2216,276],{"class":235},[221,2218,1453],{"class":309},[221,2220,313],{"class":264},[221,2222,268],{"class":235},[221,2224,2225],{"class":242},"alert",[221,2227,268],{"class":235},[221,2229,1670],{"class":264},[221,2231,276],{"class":235},[221,2233,1827],{"class":309},[221,2235,450],{"class":264},[221,2237,2238],{"class":223,"line":622},[221,2239,297],{"emptyLinePlaceholder":296},[221,2241,2242,2244,2246,2248,2250,2252,2254,2256,2258,2260,2262,2264,2266,2268,2270,2273,2275,2277,2279,2281],{"class":223,"line":677},[221,2243,1262],{"class":344},[221,2245,1365],{"class":231},[221,2247,276],{"class":235},[221,2249,1421],{"class":309},[221,2251,313],{"class":264},[221,2253,268],{"class":235},[221,2255,1718],{"class":242},[221,2257,268],{"class":235},[221,2259,326],{"class":264},[221,2261,276],{"class":235},[221,2263,1436],{"class":309},[221,2265,313],{"class":264},[221,2267,1631],{"class":309},[221,2269,313],{"class":264},[221,2271,2272],{"class":231},"second",[221,2274,276],{"class":235},[221,2276,1147],{"class":231},[221,2278,326],{"class":264},[221,2280,287],{"class":235},[221,2282,373],{"class":264},[221,2284,2285,2287,2289,2291,2293,2295,2297,2299,2301,2303,2305,2307,2309,2311,2313,2315,2317,2319,2321,2323],{"class":223,"line":717},[221,2286,1262],{"class":344},[221,2288,1365],{"class":231},[221,2290,276],{"class":235},[221,2292,1453],{"class":309},[221,2294,313],{"class":264},[221,2296,268],{"class":235},[221,2298,1460],{"class":242},[221,2300,268],{"class":235},[221,2302,362],{"class":235},[221,2304,259],{"class":235},[221,2306,1469],{"class":264},[221,2308,210],{"class":235},[221,2310,239],{"class":235},[221,2312,1766],{"class":242},[221,2314,268],{"class":235},[221,2316,370],{"class":235},[221,2318,326],{"class":264},[221,2320,276],{"class":235},[221,2322,1487],{"class":309},[221,2324,450],{"class":264},[221,2326,2327,2329,2331,2333,2335,2337,2339,2341,2343,2345,2347,2349,2351,2353,2355,2357,2359,2361,2363,2365,2367,2369],{"class":223,"line":722},[221,2328,1262],{"class":344},[221,2330,987],{"class":309},[221,2332,313],{"class":264},[221,2334,1790],{"class":231},[221,2336,276],{"class":235},[221,2338,1453],{"class":309},[221,2340,313],{"class":264},[221,2342,268],{"class":235},[221,2344,1801],{"class":242},[221,2346,268],{"class":235},[221,2348,362],{"class":235},[221,2350,259],{"class":235},[221,2352,1469],{"class":264},[221,2354,210],{"class":235},[221,2356,239],{"class":235},[221,2358,1816],{"class":242},[221,2360,268],{"class":235},[221,2362,370],{"class":235},[221,2364,1670],{"class":264},[221,2366,276],{"class":235},[221,2368,1827],{"class":309},[221,2370,450],{"class":264},[221,2372,2373,2375],{"class":223,"line":727},[221,2374,416],{"class":235},[221,2376,373],{"class":231},[128,2378,2379,2380,2383,2384,2387,2388,2391],{},"Passing ",[132,2381,2382],{},"[first.id]"," makes ",[132,2385,2386],{},"nextMessage"," wait for a different message instead of returning the first one again. Skipping by id is safer than comparing ",[132,2389,2390],{},"createdAt"," with the test machine's clock, because the two clocks differ.",[128,2393,2394],{},"Whether a resend should cancel the earlier code is your call. If both should stay valid, flip the first assertion.",[137,2396,2398],{"id":2397},"testing-a-magic-link","Testing a Magic Link",[212,2400,2402],{"className":214,"code":2401,"language":216,"meta":217,"style":217},"test('a magic link signs in once', async ({ page, request, baseURL }) => {\n  const address = newAddress()\n\n  await page.goto('\u002Fsignin')\n  await page.getByLabel('Email').fill(address)\n  await page.getByRole('button', { name: 'Email me a link' }).click()\n  const message = await nextMessage(address)\n\n  const mail = await page.context().newPage()\n  await mail.setContent(message.html.join(''))\n  const link = await mail.getByRole('link', { name: 'Sign in to Acme' }).getAttribute('href')\n  await mail.close()\n  expect(new URL(link!).origin).toBe(new URL(baseURL!).origin)\n\n  await request.get(link!)\n\n  await page.goto(link!)\n  await page.getByRole('button', { name: 'Continue' }).click()\n  await expect(page.getByRole('heading', { name: `Signed in as ${address}` })).toBeVisible()\n\n  await page.goto(link!)\n  await expect(page.getByRole('alert')).toHaveText('This link has expired')\n})\n",[132,2403,2404,2441,2453,2457,2478,2508,2551,2569,2573,2597,2625,2686,2698,2750,2754,2773,2777,2795,2838,2889,2893,2911,2951],{"__ignoreMap":217},[221,2405,2406,2408,2410,2412,2415,2417,2419,2421,2423,2425,2427,2430,2432,2435,2437,2439],{"class":223,"line":224},[221,2407,1048],{"class":309},[221,2409,313],{"class":231},[221,2411,268],{"class":235},[221,2413,2414],{"class":242},"a magic link signs in once",[221,2416,268],{"class":235},[221,2418,362],{"class":235},[221,2420,470],{"class":227},[221,2422,1362],{"class":235},[221,2424,1365],{"class":316},[221,2426,362],{"class":235},[221,2428,2429],{"class":316}," request",[221,2431,362],{"class":235},[221,2433,2434],{"class":316}," baseURL",[221,2436,563],{"class":235},[221,2438,566],{"class":227},[221,2440,329],{"class":235},[221,2442,2443,2445,2447,2449,2451],{"class":223,"line":249},[221,2444,335],{"class":227},[221,2446,556],{"class":231},[221,2448,341],{"class":235},[221,2450,1382],{"class":309},[221,2452,450],{"class":264},[221,2454,2455],{"class":223,"line":293},[221,2456,297],{"emptyLinePlaceholder":296},[221,2458,2459,2461,2463,2465,2467,2469,2471,2474,2476],{"class":223,"line":300},[221,2460,1262],{"class":344},[221,2462,1365],{"class":231},[221,2464,276],{"class":235},[221,2466,1399],{"class":309},[221,2468,313],{"class":264},[221,2470,268],{"class":235},[221,2472,2473],{"class":242},"\u002Fsignin",[221,2475,268],{"class":235},[221,2477,373],{"class":264},[221,2479,2480,2482,2484,2486,2488,2490,2492,2494,2496,2498,2500,2502,2504,2506],{"class":223,"line":332},[221,2481,1262],{"class":344},[221,2483,1365],{"class":231},[221,2485,276],{"class":235},[221,2487,1421],{"class":309},[221,2489,313],{"class":264},[221,2491,268],{"class":235},[221,2493,18],{"class":242},[221,2495,268],{"class":235},[221,2497,326],{"class":264},[221,2499,276],{"class":235},[221,2501,1436],{"class":309},[221,2503,313],{"class":264},[221,2505,480],{"class":231},[221,2507,373],{"class":264},[221,2509,2510,2512,2514,2516,2518,2520,2522,2524,2526,2528,2530,2532,2534,2536,2539,2541,2543,2545,2547,2549],{"class":223,"line":376},[221,2511,1262],{"class":344},[221,2513,1365],{"class":231},[221,2515,276],{"class":235},[221,2517,1453],{"class":309},[221,2519,313],{"class":264},[221,2521,268],{"class":235},[221,2523,1460],{"class":242},[221,2525,268],{"class":235},[221,2527,362],{"class":235},[221,2529,259],{"class":235},[221,2531,1469],{"class":264},[221,2533,210],{"class":235},[221,2535,239],{"class":235},[221,2537,2538],{"class":242},"Email me a link",[221,2540,268],{"class":235},[221,2542,370],{"class":235},[221,2544,326],{"class":264},[221,2546,276],{"class":235},[221,2548,1487],{"class":309},[221,2550,450],{"class":264},[221,2552,2553,2555,2557,2559,2561,2563,2565,2567],{"class":223,"line":397},[221,2554,335],{"class":227},[221,2556,1500],{"class":231},[221,2558,341],{"class":235},[221,2560,345],{"class":344},[221,2562,1231],{"class":309},[221,2564,313],{"class":264},[221,2566,480],{"class":231},[221,2568,373],{"class":264},[221,2570,2571],{"class":223,"line":437},[221,2572,297],{"emptyLinePlaceholder":296},[221,2574,2575,2577,2579,2581,2583,2585,2587,2589,2591,2593,2595],{"class":223,"line":453},[221,2576,335],{"class":227},[221,2578,1568],{"class":231},[221,2580,341],{"class":235},[221,2582,345],{"class":344},[221,2584,1365],{"class":231},[221,2586,276],{"class":235},[221,2588,1579],{"class":309},[221,2590,1126],{"class":264},[221,2592,276],{"class":235},[221,2594,1586],{"class":309},[221,2596,450],{"class":264},[221,2598,2599,2601,2603,2605,2607,2609,2611,2613,2615,2617,2619,2621,2623],{"class":223,"line":459},[221,2600,1262],{"class":344},[221,2602,1568],{"class":231},[221,2604,276],{"class":235},[221,2606,1600],{"class":309},[221,2608,313],{"class":264},[221,2610,1530],{"class":231},[221,2612,276],{"class":235},[221,2614,1609],{"class":231},[221,2616,276],{"class":235},[221,2618,1614],{"class":309},[221,2620,313],{"class":264},[221,2622,1619],{"class":235},[221,2624,914],{"class":264},[221,2626,2627,2629,2632,2634,2636,2638,2640,2642,2644,2646,2649,2651,2653,2655,2657,2659,2661,2664,2666,2668,2670,2672,2675,2677,2679,2682,2684],{"class":223,"line":464},[221,2628,335],{"class":227},[221,2630,2631],{"class":231}," link",[221,2633,341],{"class":235},[221,2635,345],{"class":344},[221,2637,1568],{"class":231},[221,2639,276],{"class":235},[221,2641,1453],{"class":309},[221,2643,313],{"class":264},[221,2645,268],{"class":235},[221,2647,2648],{"class":242},"link",[221,2650,268],{"class":235},[221,2652,362],{"class":235},[221,2654,259],{"class":235},[221,2656,1469],{"class":264},[221,2658,210],{"class":235},[221,2660,239],{"class":235},[221,2662,2663],{"class":242},"Sign in to Acme",[221,2665,268],{"class":235},[221,2667,370],{"class":235},[221,2669,326],{"class":264},[221,2671,276],{"class":235},[221,2673,2674],{"class":309},"getAttribute",[221,2676,313],{"class":264},[221,2678,268],{"class":235},[221,2680,2681],{"class":242},"href",[221,2683,268],{"class":235},[221,2685,373],{"class":264},[221,2687,2688,2690,2692,2694,2696],{"class":223,"line":491},[221,2689,1262],{"class":344},[221,2691,1568],{"class":231},[221,2693,276],{"class":235},[221,2695,1693],{"class":309},[221,2697,450],{"class":264},[221,2699,2700,2702,2704,2707,2710,2712,2714,2716,2718,2720,2723,2725,2727,2729,2731,2733,2735,2737,2740,2742,2744,2746,2748],{"class":223,"line":529},[221,2701,1542],{"class":309},[221,2703,313],{"class":264},[221,2705,2706],{"class":235},"new",[221,2708,2709],{"class":309}," URL",[221,2711,313],{"class":264},[221,2713,2648],{"class":231},[221,2715,287],{"class":235},[221,2717,326],{"class":264},[221,2719,276],{"class":235},[221,2721,2722],{"class":231},"origin",[221,2724,326],{"class":264},[221,2726,276],{"class":235},[221,2728,1675],{"class":309},[221,2730,313],{"class":264},[221,2732,2706],{"class":235},[221,2734,2709],{"class":309},[221,2736,313],{"class":264},[221,2738,2739],{"class":231},"baseURL",[221,2741,287],{"class":235},[221,2743,326],{"class":264},[221,2745,276],{"class":235},[221,2747,2722],{"class":231},[221,2749,373],{"class":264},[221,2751,2752],{"class":223,"line":583},[221,2753,297],{"emptyLinePlaceholder":296},[221,2755,2756,2758,2760,2762,2765,2767,2769,2771],{"class":223,"line":622},[221,2757,1262],{"class":344},[221,2759,2429],{"class":231},[221,2761,276],{"class":235},[221,2763,2764],{"class":309},"get",[221,2766,313],{"class":264},[221,2768,2648],{"class":231},[221,2770,287],{"class":235},[221,2772,373],{"class":264},[221,2774,2775],{"class":223,"line":677},[221,2776,297],{"emptyLinePlaceholder":296},[221,2778,2779,2781,2783,2785,2787,2789,2791,2793],{"class":223,"line":717},[221,2780,1262],{"class":344},[221,2782,1365],{"class":231},[221,2784,276],{"class":235},[221,2786,1399],{"class":309},[221,2788,313],{"class":264},[221,2790,2648],{"class":231},[221,2792,287],{"class":235},[221,2794,373],{"class":264},[221,2796,2797,2799,2801,2803,2805,2807,2809,2811,2813,2815,2817,2819,2821,2823,2826,2828,2830,2832,2834,2836],{"class":223,"line":722},[221,2798,1262],{"class":344},[221,2800,1365],{"class":231},[221,2802,276],{"class":235},[221,2804,1453],{"class":309},[221,2806,313],{"class":264},[221,2808,268],{"class":235},[221,2810,1460],{"class":242},[221,2812,268],{"class":235},[221,2814,362],{"class":235},[221,2816,259],{"class":235},[221,2818,1469],{"class":264},[221,2820,210],{"class":235},[221,2822,239],{"class":235},[221,2824,2825],{"class":242},"Continue",[221,2827,268],{"class":235},[221,2829,370],{"class":235},[221,2831,326],{"class":264},[221,2833,276],{"class":235},[221,2835,1487],{"class":309},[221,2837,450],{"class":264},[221,2839,2840,2842,2844,2846,2848,2850,2852,2854,2856,2858,2860,2862,2864,2866,2868,2870,2873,2875,2877,2879,2881,2883,2885,2887],{"class":223,"line":727},[221,2841,1262],{"class":344},[221,2843,987],{"class":309},[221,2845,313],{"class":264},[221,2847,1790],{"class":231},[221,2849,276],{"class":235},[221,2851,1453],{"class":309},[221,2853,313],{"class":264},[221,2855,268],{"class":235},[221,2857,1801],{"class":242},[221,2859,268],{"class":235},[221,2861,362],{"class":235},[221,2863,259],{"class":235},[221,2865,1469],{"class":264},[221,2867,210],{"class":235},[221,2869,682],{"class":235},[221,2871,2872],{"class":242},"Signed in as ",[221,2874,422],{"class":235},[221,2876,480],{"class":231},[221,2878,432],{"class":235},[221,2880,370],{"class":235},[221,2882,1670],{"class":264},[221,2884,276],{"class":235},[221,2886,1827],{"class":309},[221,2888,450],{"class":264},[221,2890,2891],{"class":223,"line":777},[221,2892,297],{"emptyLinePlaceholder":296},[221,2894,2895,2897,2899,2901,2903,2905,2907,2909],{"class":223,"line":800},[221,2896,1262],{"class":344},[221,2898,1365],{"class":231},[221,2900,276],{"class":235},[221,2902,1399],{"class":309},[221,2904,313],{"class":264},[221,2906,2648],{"class":231},[221,2908,287],{"class":235},[221,2910,373],{"class":264},[221,2912,2913,2915,2917,2919,2921,2923,2925,2927,2929,2931,2933,2935,2937,2940,2942,2944,2947,2949],{"class":223,"line":857},[221,2914,1262],{"class":344},[221,2916,987],{"class":309},[221,2918,313],{"class":264},[221,2920,1790],{"class":231},[221,2922,276],{"class":235},[221,2924,1453],{"class":309},[221,2926,313],{"class":264},[221,2928,268],{"class":235},[221,2930,2225],{"class":242},[221,2932,268],{"class":235},[221,2934,1670],{"class":264},[221,2936,276],{"class":235},[221,2938,2939],{"class":309},"toHaveText",[221,2941,313],{"class":264},[221,2943,268],{"class":235},[221,2945,2946],{"class":242},"This link has expired",[221,2948,268],{"class":235},[221,2950,373],{"class":264},[221,2952,2953,2955],{"class":223,"line":917},[221,2954,416],{"class":235},[221,2956,373],{"class":231},[128,2958,2959],{},"Three checks in one test:",[145,2961,2962,2970,2988],{},[148,2963,2964,2967,2968,276],{},[151,2965,2966],{},"The origin."," A link built from the wrong base URL points at production, or at ",[132,2969,134],{},[148,2971,2972,2975,2976,2979,2980,2983,2984,2987],{},[151,2973,2974],{},"A scanner's visit."," Mail filters and link previewers fetch the URLs in a message before the recipient opens it. If a ",[132,2977,2978],{},"GET"," alone signs the user in, the scanner spends the link and the person sees \"expired\". ",[132,2981,2982],{},"request.get"," plays the scanner, and the link has to work afterwards. This app passes because the link opens a page with a Continue button, and only that button's ",[132,2985,2986],{},"POST"," uses the token.",[148,2989,2990,2993],{},[151,2991,2992],{},"Single use."," The second visit is refused.",[128,2995,2996,2999,3000,3003,3004,276],{},[132,2997,2998],{},"getAttribute('href')"," returns the URL as the browser parsed it, so ",[132,3001,3002],{},"&amp;"," in the markup comes back as ",[132,3005,3006],{},"&",[137,3008,3010],{"id":3009},"asserting-that-no-email-arrives","Asserting That No Email Arrives",[128,3012,3013],{},"Some tests pass when nothing arrives: a password reset for an address with no account, a resend past the rate limit, a user who unsubscribed.",[212,3015,3017],{"className":214,"code":3016,"language":216,"meta":217,"style":217},"test('an unknown address gets no reset email', async ({ page }) => {\n  const address = newAddress()\n\n  await page.goto('\u002Fforgot-password')\n  await page.getByLabel('Email').fill(address)\n  await page.getByRole('button', { name: 'Send reset link' }).click()\n  await expect(page.getByText('If that address has an account')).toBeVisible()\n\n  await page.waitForTimeout(5000)\n  expect(await findMessage(inbox, address)).toBeUndefined()\n})\n",[132,3018,3019,3046,3058,3062,3083,3113,3156,3188,3192,3210,3237],{"__ignoreMap":217},[221,3020,3021,3023,3025,3027,3030,3032,3034,3036,3038,3040,3042,3044],{"class":223,"line":224},[221,3022,1048],{"class":309},[221,3024,313],{"class":231},[221,3026,268],{"class":235},[221,3028,3029],{"class":242},"an unknown address gets no reset email",[221,3031,268],{"class":235},[221,3033,362],{"class":235},[221,3035,470],{"class":227},[221,3037,1362],{"class":235},[221,3039,1365],{"class":316},[221,3041,563],{"class":235},[221,3043,566],{"class":227},[221,3045,329],{"class":235},[221,3047,3048,3050,3052,3054,3056],{"class":223,"line":249},[221,3049,335],{"class":227},[221,3051,556],{"class":231},[221,3053,341],{"class":235},[221,3055,1382],{"class":309},[221,3057,450],{"class":264},[221,3059,3060],{"class":223,"line":293},[221,3061,297],{"emptyLinePlaceholder":296},[221,3063,3064,3066,3068,3070,3072,3074,3076,3079,3081],{"class":223,"line":300},[221,3065,1262],{"class":344},[221,3067,1365],{"class":231},[221,3069,276],{"class":235},[221,3071,1399],{"class":309},[221,3073,313],{"class":264},[221,3075,268],{"class":235},[221,3077,3078],{"class":242},"\u002Fforgot-password",[221,3080,268],{"class":235},[221,3082,373],{"class":264},[221,3084,3085,3087,3089,3091,3093,3095,3097,3099,3101,3103,3105,3107,3109,3111],{"class":223,"line":332},[221,3086,1262],{"class":344},[221,3088,1365],{"class":231},[221,3090,276],{"class":235},[221,3092,1421],{"class":309},[221,3094,313],{"class":264},[221,3096,268],{"class":235},[221,3098,18],{"class":242},[221,3100,268],{"class":235},[221,3102,326],{"class":264},[221,3104,276],{"class":235},[221,3106,1436],{"class":309},[221,3108,313],{"class":264},[221,3110,480],{"class":231},[221,3112,373],{"class":264},[221,3114,3115,3117,3119,3121,3123,3125,3127,3129,3131,3133,3135,3137,3139,3141,3144,3146,3148,3150,3152,3154],{"class":223,"line":376},[221,3116,1262],{"class":344},[221,3118,1365],{"class":231},[221,3120,276],{"class":235},[221,3122,1453],{"class":309},[221,3124,313],{"class":264},[221,3126,268],{"class":235},[221,3128,1460],{"class":242},[221,3130,268],{"class":235},[221,3132,362],{"class":235},[221,3134,259],{"class":235},[221,3136,1469],{"class":264},[221,3138,210],{"class":235},[221,3140,239],{"class":235},[221,3142,3143],{"class":242},"Send reset link",[221,3145,268],{"class":235},[221,3147,370],{"class":235},[221,3149,326],{"class":264},[221,3151,276],{"class":235},[221,3153,1487],{"class":309},[221,3155,450],{"class":264},[221,3157,3158,3160,3162,3164,3166,3168,3171,3173,3175,3178,3180,3182,3184,3186],{"class":223,"line":397},[221,3159,1262],{"class":344},[221,3161,987],{"class":309},[221,3163,313],{"class":264},[221,3165,1790],{"class":231},[221,3167,276],{"class":235},[221,3169,3170],{"class":309},"getByText",[221,3172,313],{"class":264},[221,3174,268],{"class":235},[221,3176,3177],{"class":242},"If that address has an account",[221,3179,268],{"class":235},[221,3181,1670],{"class":264},[221,3183,276],{"class":235},[221,3185,1827],{"class":309},[221,3187,450],{"class":264},[221,3189,3190],{"class":223,"line":437},[221,3191,297],{"emptyLinePlaceholder":296},[221,3193,3194,3196,3198,3200,3203,3205,3208],{"class":223,"line":453},[221,3195,1262],{"class":344},[221,3197,1365],{"class":231},[221,3199,276],{"class":235},[221,3201,3202],{"class":309},"waitForTimeout",[221,3204,313],{"class":264},[221,3206,3207],{"class":1190},"5000",[221,3209,373],{"class":264},[221,3211,3212,3214,3216,3218,3220,3222,3224,3226,3228,3230,3232,3235],{"class":223,"line":459},[221,3213,1542],{"class":309},[221,3215,313],{"class":264},[221,3217,1636],{"class":344},[221,3219,736],{"class":309},[221,3221,313],{"class":264},[221,3223,702],{"class":231},[221,3225,362],{"class":235},[221,3227,556],{"class":231},[221,3229,1670],{"class":264},[221,3231,276],{"class":235},[221,3233,3234],{"class":309},"toBeUndefined",[221,3236,450],{"class":264},[221,3238,3239,3241],{"class":223,"line":464},[221,3240,416],{"class":235},[221,3242,373],{"class":231},[128,3244,3245],{},"There's no event to wait for when nothing should happen. Wait a fixed time, longer than your other tests take to see a message, then check once.",[137,3247,3249],{"id":3248},"more-cases","More Cases",[3251,3252,3253,3268],"table",{},[3254,3255,3256],"thead",{},[3257,3258,3259,3263,3265],"tr",{},[3260,3261,3262],"th",{},"Case",[3260,3264,9],{},[3260,3266,3267],{},"Expect",[3269,3270,3271,3283,3298,3309,3319],"tbody",{},[3257,3272,3273,3277,3280],{},[3274,3275,3276],"td",{},"Wrong code",[3274,3278,3279],{},"Enter six digits that weren't sent",[3274,3281,3282],{},"An error, and the real code still works after it",[3257,3284,3285,3288,3295],{},[3274,3286,3287],{},"Expired code",[3274,3289,3290,3291,3294],{},"Run the test environment with a short lifetime, like ",[132,3292,3293],{},"OTP_TTL_SECONDS=3",", and wait it out",[3274,3296,3297],{},"The same error as a wrong code",[3257,3299,3300,3303,3306],{},[3274,3301,3302],{},"Used code",[3274,3304,3305],{},"Verify, then submit the same code in a new session",[3274,3307,3308],{},"Refused",[3257,3310,3311,3314,3317],{},[3274,3312,3313],{},"Someone else's code",[3274,3315,3316],{},"Sign up as two addresses and enter the first one's code for the second",[3274,3318,3308],{},[3257,3320,3321,3324,3327],{},[3274,3322,3323],{},"Too many wrong attempts",[3274,3325,3326],{},"Enter wrong codes up to your limit, then the right one",[3274,3328,3329],{},"Refused until a new code is requested",[137,3331,3333],{"id":3332},"other-runners","Other Runners",[128,3335,3336,3337,3340,3341,3345,3346,3350,3351,3355],{},"The helper is plain ",[132,3338,3339],{},"fetch",", so it runs anywhere Node does. Cypress has to keep the API key out of the browser, so the wait runs in a task: the ",[160,3342,3344],{"href":3343},"\u002Fdocs\u002Fguides\u002Fcypress\u002F","Cypress guide"," has it. For pytest, the ",[160,3347,3349],{"href":3348},"\u002Fdocs\u002Fguides\u002Femail-testing-api\u002F#in-a-test","API quickstart"," has the same wait as a fixture. The ",[160,3352,3354],{"href":3353},"\u002Fdocs\u002Fguides\u002Fe2e\u002F#in-ci","Playwright guide"," shows how to start the app with its SMTP settings for a CI run.",[137,3357,3359],{"id":3358},"when-it-fails","When It Fails",[3251,3361,3362,3372],{},[3254,3363,3364],{},[3257,3365,3366,3369],{},[3260,3367,3368],{},"Symptom",[3260,3370,3371],{},"Cause",[3269,3373,3374,3387,3395,3409,3417],{},[3257,3375,3376,3379],{},[3274,3377,3378],{},"The app errors when it sends",[3274,3380,3381,3383,3384,3386],{},[132,3382,157],{}," refuses recipients that aren't sandbox accounts. The account behind the alias, ",[132,3385,181],{}," here, has to exist",[3257,3388,3389,3392],{},[3274,3390,3391],{},"No email, and the app sent without error",[3274,3393,3394],{},"The app still sends through its usual provider, and the address isn't on a domain whose MX points at the sandbox",[3257,3396,3397,3403],{},[3274,3398,3399,1854,3401],{},[132,3400,1631],{},[132,3402,964],{},[3274,3404,3405,3406,3408],{},"The email has no plain text part, so ",[132,3407,1147],{}," is empty. Read the code from the rendered HTML",[3257,3410,3411,3414],{},[3274,3412,3413],{},"The wrong digits",[3274,3415,3416],{},"The pattern is too loose. Anchor it to the words around the code",[3257,3418,3419,3422],{},[3274,3420,3421],{},"Passes alone, fails in parallel",[3274,3423,3424],{},"Two tests share an address. Give each its own alias",[3426,3427,3428],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":217,"searchDepth":249,"depth":249,"links":3430},[3431,3432,3433,3434,3435,3436,3437,3438,3439],{"id":139,"depth":249,"text":140},{"id":202,"depth":249,"text":203},{"id":971,"depth":249,"text":972},{"id":1877,"depth":249,"text":1878},{"id":2397,"depth":249,"text":2398},{"id":3009,"depth":249,"text":3010},{"id":3248,"depth":249,"text":3249},{"id":3332,"depth":249,"text":3333},{"id":3358,"depth":249,"text":3359},"Read one-time codes and magic links from the real email over a REST API, then test resend, reuse, and single-use links. Playwright specs you can copy.","md",{},{"title":93},{"title":123,"description":3440},"MGhzJgSvxr1AjK9aC-mDXqvJQsjQJygXJuuoTCPR73E",[3447,3449],{"title":89,"path":90,"stem":91,"description":3448,"children":-1},"Why a 25 MB limit fits about 18 MB of attachments, the limits Gmail, Microsoft 365, SES, SendGrid, Mailgun, and Postmark publish, and how to test the boundary.",{"title":97,"path":98,"stem":99,"description":3450,"children":-1},"IMAP works on the server's copy of a mailbox, POP3 downloads it. Ports, the commands to type into openssl, and curl, Python, and Node scripts for both.",1794400213181]