[{"data":1,"prerenderedAt":575},["ShallowReactive",2],{"release-20.4.0":3,"releases-nav":509,"nav-compare":547,"editor-1tc3u0y":557,"editor-jpivk9":559,"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0":561},{"id":4,"title":5,"body":6,"date":497,"description":128,"extension":498,"headline":207,"meta":499,"navigation":501,"path":502,"playwright":503,"seo":504,"stem":505,"supports":506,"version":507,"__hash__":508},"releases\u002Freleases\u002F20.4.0.md","Browser 20.4.0",{"type":7,"value":8,"toc":482},"minimark",[9,14,27,31,37,47,52,63,68,80,85,88,97,100,113,116,119,129,132,141,156,162,166,473],[10,11,13],"h2",{"id":12},"most-important-enhancements","Most important enhancements",[15,16,18,19,26],"h3",{"id":17},"several-small-issues-found-while-auditing-the-docs-against-the-code-5135","Several small issues found while auditing the docs against the code (",[20,21,25],"a",{"href":22,"rel":23},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5135",[24],"nofollow","#5135",")",[28,29,30],"p",{},"This issue covers several fixes:",[28,32,33],{},[34,35,36],"strong",{},"Security",[38,39,40,44],"ul",{},[41,42,43],"li",{},"Storage keywords built JavaScript by string interpolation. The six\nlocal\u002Fsession storage keywords embedded the key straight into the expression\nevaluated in the page, so a key containing \" did not merely break the\nsyntax, it executed: x\"), (window.pwned = 42), window.localStorage.getItem(\"y\nruns that assignment. The three sites using repr() instead had a quieter\nfailure — for any non-printable code point above U+FFFF, repr() emits\n\\U000e0001, which JavaScript reads as an identity escape, so the page\nsilently addressed a different key. All six now use json.dumps.",[41,45,46],{},"Get Credential wrote the WebAuthn private key to playwright-log.txt.\nThe Node side logged the whole credential object, and that log is written\nunder default configuration. The Python side already wraps the key material in\nSecret() to keep it out of the RF log; the Node line defeated that. It logs\nthe id only.",[28,48,49],{},[34,50,51],{},"Bugs",[38,53,54,57,60],{},[41,55,56],{},"JavaScript extension keywords always required an open browser.\ngetActiveBrowser() throws when nothing is open, so the optional chaining\nguarding it never ran — including for a keyword whose only argument is\nplaywright. atest\u002F...\u002Ffunky.js's createRemoteBrowser is exactly that\nshape, and only passes today because an earlier test leaves a browser open.\nThe browser is now resolved only when the keyword asks for page, context\nor browser.",[41,58,59],{},"Add Locator Handler Custom emptied the spec it was given. It popped keys\nout of the caller's dictionary, so a &{dict} variable could be used once;\nthe second call failed with Action must be defined in the handler\nspecification, and the variable stayed broken for the rest of the suite.\nListing the same dictionary twice in one call failed the same way. It works on\na copy now.",[41,61,62],{},"Merge Coverage Reports discarded name= when config_file= was also\ngiven. ⚠️ The one change that can alter a passing suite — see below.",[28,64,65],{},[34,66,67],{},"Documentation",[38,69,70,73],{},[41,71,72],{},"Emulate Media was annotated -> None but returns a dict, and RF drops a\nNone return type from the spec entirely, so the keyword reference said it\nreturned nothing. Get Page Errors was annotated -> dict but returns a\nlist. Both now declare what they return; no runtime change.",[41,74,75,76],{},"getElement and findLocator still documented the element=",[77,78,79],"uuid",{}," selector\nsyntax, removed in 17.0.0. Comments only.",[28,81,82],{},[34,83,84],{},"One behavior change",[28,86,87],{},"Merge Coverage Reports now honours an explicit name when a config_file is\nalso supplied. Previously the name was overwritten with the default report\ntitle, so name= worked without a config file and was silently ignored with\none — contradicting the function's own merge order, where keyword arguments\noverride the config file for every other option.",[15,89,91,92,26],{"id":90},"raise-minimum-needed-robot-framework-version-to-711-5133","Raise minimum needed Robot Framework version to 7.1.1 (",[20,93,96],{"href":94,"rel":95},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5133",[24],"#5133",[28,98,99],{},"To be able to ease the work needed for making Python support easier, it was\ndecided to drop support for Robot Framework 6.1.x. This also allowed us to clean\nsome internal conversion logic and architecture of the library better. I understand\nif someone sees this a backwards incompatible change, but the 6.1.1 was released\n28. July 2023, which is over three years ago. If you have not been able to update\nyour Robot Framework version, you can still use the older version of Browser\nlibrary, but we strongly encourage you to update.",[15,101,103,107,108,26],{"id":102},"set-presenter-mode-silently-fall-back-to-defaults-when-invalid-dict-given-5143",[104,105,106],"code",{},"Set Presenter Mode"," silently fall back to defaults, when invalid dict given (",[20,109,112],{"href":110,"rel":111},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5143",[24],"#5143",[28,114,115],{},"The keyword Set Presenter Mode and the init arg enable_presenter_mode just silently ignored everything that is not 100% correct.",[28,117,118],{},"Any Strings were just True and therefore 100% default. Any actual dict,\nmust be correct, otherwise it failed.",[120,121,126],"pre",{"className":122,"code":124,"language":125},[123],"language-text","*** Test Cases ***\nAll following calls will end up in full default config.\n  Set Presenter Mode    {\"color\": \"red\"}   #does not have all keys, therefore full defaults\n  Set Presenter Mode    {\"duration\": \"5 seconds\", \"width\": \"6px\", \"style\": \"dotted\", \"color\": \"red\"    #missing closing {\n  Set Presenter Mode    What ever you put in here, except of an invalid dict.    #will also be a string... and therefore Truthy\n","text",[104,127,124],{"__ignoreMap":128},"",[28,130,131],{},"The documentation however was talking about default which did actually only exist in case of a Truthy non-dict given.",[15,133,135,136,26],{"id":134},"keywords-called-from-python-convert-plain-values-like-they-do-in-robot-framework-5145","Keywords called from Python convert plain values, like they do in Robot Framework (",[20,137,140],{"href":138,"rel":139},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5145",[24],"#5145",[28,142,143,144,149,150,155],{},"The Browser library keyword have been part of the public API for the start, but using keyword that example takes\n",[20,145,148],{"href":146,"rel":147},"https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Fenum.html",[24],"Enums"," or\n",[20,151,154],{"href":152,"rel":153},"https:\u002F\u002Fdocs.python.org\u002F3\u002Flibrary\u002Fdatetime.html#timedelta-objects",[24],"timedelta","\nare unnecessary hard from Python side. But they are excellent when used\nRobot Framework test data, because Robot Framework does automatic conversion\nand IDE have good support for Enum types. So all that makes the usage great\nfrom Robot Framework side, makes it harder from Python side. With this change\nwhen keyword methods are called from Python, we now accept string, like the\nusage from Robot Framework side. Example",[120,157,160],{"className":158,"code":159,"language":125},[123],"browser.click(\"\u002F\u002Fbutton\", \"middle\")                    # was: MouseButton.middle\nbrowser.click_with_options(\"\u002F\u002Fbutton\", delay=\"1.5s\")   # was: timedelta(seconds=1.5)\nbrowser.get_text(\"h1\", \"==\", \"Login Page\")             # was: AssertionOperator[\"==\"]\n",[104,161,159],{"__ignoreMap":128},[10,163,165],{"id":164},"full-list-of-fixes-and-enhancements","Full list of fixes and enhancements",[167,168,169,188],"table",{},[170,171,172],"thead",{},[173,174,175,179,182,185],"tr",{},[176,177,178],"th",{},"ID",[176,180,181],{},"Type",[176,183,184],{},"Priority",[176,186,187],{},"Summary",[189,190,191,208,223,240,254,271,287,304,321,337,353,369,385,416,443],"tbody",{},[173,192,193,199,202,205],{},[194,195,196],"td",{},[20,197,25],{"href":22,"rel":198},[24],[194,200,201],{},"bug",[194,203,204],{},"critical",[194,206,207],{},"Several small issues found while auditing the docs against the code",[173,209,210,215,218,220],{},[194,211,212],{},[20,213,96],{"href":94,"rel":214},[24],[194,216,217],{},"feature",[194,219,204],{},[194,221,222],{},"Raise minimum needed Robot Framework version to 7.1.1",[173,224,225,230,232,235],{},[194,226,227],{},[20,228,112],{"href":110,"rel":229},[24],[194,231,201],{},[194,233,234],{},"high",[194,236,237,239],{},[104,238,106],{}," silently fall back to defaults, when invalid dict given",[173,241,242,247,249,251],{},[194,243,244],{},[20,245,140],{"href":138,"rel":246},[24],[194,248,217],{},[194,250,234],{},[194,252,253],{},"Keywords called from Python convert plain values, like they do in Robot Framework",[173,255,256,263,265,268],{},[194,257,258],{},[20,259,262],{"href":260,"rel":261},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F1037",[24],"#1037",[194,264,201],{},[194,266,267],{},"medium",[194,269,270],{},"Playwright process connection in container fails when proxy is set ..   client_channel\u002Flb_policy\u002Fpick_first\u002Fpick_first.cc\",\"file_line\":397,\"grpc_status\":14",[173,272,273,280,282,284],{},[194,274,275],{},[20,276,279],{"href":277,"rel":278},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F3367",[24],"#3367",[194,281,201],{},[194,283,267],{},[194,285,286],{},"\"Stream removed\" issue happens once \"Handle Future Dialogs\" is used more than once",[173,288,289,296,299,301],{},[194,290,291],{},[20,292,295],{"href":293,"rel":294},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F4095",[24],"#4095",[194,297,298],{},"enhancement",[194,300,267],{},[194,302,303],{},"Screenshots in portrait mode (phone) too big in the test report (hardcoded 800px)",[173,305,306,313,315,318],{},[194,307,308],{},[20,309,312],{"href":310,"rel":311},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5142",[24],"#5142",[194,314,201],{},[194,316,317],{},"---",[194,319,320],{},"Review and Fix typos and formatting issues in library documentation (Libdoc)",[173,322,323,330,332,334],{},[194,324,325],{},[20,326,329],{"href":327,"rel":328},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5154",[24],"#5154",[194,331,201],{},[194,333,317],{},[194,335,336],{},"Keyword call banner is silently disabled when Browser is imported with AS alias or subclassed",[173,338,339,346,348,350],{},[194,340,341],{},[20,342,345],{"href":343,"rel":344},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5169",[24],"#5169",[194,347,201],{},[194,349,317],{},[194,351,352],{},"Keyword call banner muting and secret log suppression are disabled when keyword names are translated",[173,354,355,362,364,366],{},[194,356,357],{},[20,358,361],{"href":359,"rel":360},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5170",[24],"#5170",[194,363,201],{},[194,365,317],{},[194,367,368],{},"Keyword call banner paints a resolved secret into the page before Fill Secret rejects it",[173,370,371,378,380,382],{},[194,372,373],{},[20,374,377],{"href":375,"rel":376},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5172",[24],"#5172",[194,379,201],{},[194,381,317],{},[194,383,384],{},"Create Credential paints privateKey and publicKey into the keyword call banner in clear text",[173,386,387,394,396,398],{},[194,388,389],{},[20,390,393],{"href":391,"rel":392},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5101",[24],"#5101",[194,395,217],{},[194,397,317],{},[194,399,400,401,404,405,408,409,412,413],{},"Add ",[104,402,403],{},"mode",", ",[104,406,407],{},"depth"," and ",[104,410,411],{},"boxes"," arguments to ",[104,414,415],{},"Get Aria Snapshot",[173,417,418,425,427,429],{},[194,419,420],{},[20,421,424],{"href":422,"rel":423},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5110",[24],"#5110",[194,426,217],{},[194,428,317],{},[194,430,400,431,434,435,438,439,442],{},[104,432,433],{},"delay="," argument to ",[104,436,437],{},"Keyboard Key"," for the ",[104,440,441],{},"press"," action",[173,444,445,452,454,456],{},[194,446,447],{},[20,448,451],{"href":449,"rel":450},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues\u002F5117",[24],"#5117",[194,453,217],{},[194,455,317],{},[194,457,400,458,461,462,465,466,469,470],{},[104,459,460],{},"Set Storage State"," keyword and ",[104,463,464],{},"indexedDB=","\u002F",[104,467,468],{},"credentials="," arguments on ",[104,471,472],{},"Save Storage State",[28,474,475,476,481],{},"Altogether 15 issues. View on the ",[20,477,480],{"href":478,"rel":479},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Fissues?q=milestone%3Av20.4.0",[24],"issue tracker",".",{"title":128,"searchDepth":483,"depth":483,"links":484},2,[485,496],{"id":12,"depth":483,"text":13,"children":486},[487,490,492,494],{"id":17,"depth":488,"text":489},3,"Several small issues found while auditing the docs against the code (#5135)",{"id":90,"depth":488,"text":491},"Raise minimum needed Robot Framework version to 7.1.1 (#5133)",{"id":102,"depth":488,"text":493},"Set Presenter Mode silently fall back to defaults, when invalid dict given (#5143)",{"id":134,"depth":488,"text":495},"Keywords called from Python convert plain values, like they do in Robot Framework (#5145)",{"id":164,"depth":483,"text":165},"August 19, 2026","md",{"source":500},"Generated from the library repository by scripts\u002Fbuild-releases.ts",true,"\u002Freleases\u002F20.4.0","1.62.1",{"title":5,"description":128},"releases\u002F20.4.0","Python 3.10+, Node 22\u002F24 LTS and Node 26, and Robot Framework 7.1.1+","20.4.0","2ianU3by72rmw4WSJVx7aQXGa1FiInHKKApF-tnjW48",[510,513,516,519,522,525,528,531,534,537,540,543,546],{"path":511,"version":512},"\u002Freleases\u002F19.12.4","19.12.4",{"path":514,"version":515},"\u002Freleases\u002F19.12.5","19.12.5",{"path":517,"version":518},"\u002Freleases\u002F19.12.6","19.12.6",{"path":520,"version":521},"\u002Freleases\u002F19.12.7","19.12.7",{"path":523,"version":524},"\u002Freleases\u002F19.13.0","19.13.0",{"path":526,"version":527},"\u002Freleases\u002F19.14.2","19.14.2",{"path":529,"version":530},"\u002Freleases\u002F19.15.0","19.15.0",{"path":532,"version":533},"\u002Freleases\u002F19.15.1","19.15.1",{"path":535,"version":536},"\u002Freleases\u002F20.0.0","20.0.0",{"path":538,"version":539},"\u002Freleases\u002F20.1.0","20.1.0",{"path":541,"version":542},"\u002Freleases\u002F20.2.0","20.2.0",{"path":544,"version":545},"\u002Freleases\u002F20.3.0","20.3.0",{"path":502,"version":507},[548,551,554],{"to":549,"label":550},"\u002Fwhy\u002Fvs-cypress","vs Cypress",{"to":552,"label":553},"\u002Fwhy\u002Fvs-playwright","vs Playwright Test",{"to":555,"label":556},"\u002Fwhy\u002Fvs-seleniumlibrary","vs SeleniumLibrary",[558],"\u003Cspan class=\"line\">\u003Cspan>*** Test Cases ***\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan>All following calls will end up in full default config.\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan>  Set Presenter Mode    {\"color\": \"red\"}   #does not have all keys, therefore full defaults\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan>  Set Presenter Mode    {\"duration\": \"5 seconds\", \"width\": \"6px\", \"style\": \"dotted\", \"color\": \"red\"    #missing closing {\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan>  Set Presenter Mode    What ever you put in here, except of an invalid dict.    #will also be a string... and therefore Truthy\u003C\u002Fspan>\u003C\u002Fspan>",[560],"\u003Cspan class=\"line\">\u003Cspan>browser.click(\"\u002F\u002Fbutton\", \"middle\")                    # was: MouseButton.middle\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan>browser.click_with_options(\"\u002F\u002Fbutton\", delay=\"1.5s\")   # was: timedelta(seconds=1.5)\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan>browser.get_text(\"h1\", \"==\", \"Login Page\")             # was: AssertionOperator[\"==\"]\u003C\u002Fspan>\u003C\u002Fspan>",["Island",562],{"key":563,"result":564},"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0",{"head":565},{"style":566},[567,569,571,573],{"innerHTML":568},".site-footer[data-v-8bb1d4ae]{border-top:1px solid var(--line);background:var(--chrome);padding:var(--sp-8) var(--gutter) var(--sp-10);gap:var(--sp-6);flex-direction:column;display:flex}.links[data-v-8bb1d4ae]{gap:var(--sp-4);grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));max-width:62rem;display:grid}.links a[data-v-8bb1d4ae]{align-items:flex-start;gap:var(--sp-3);padding:var(--sp-3);border-bottom:1px solid var(--line);border-radius:var(--radius-sm);background:var(--panel);color:var(--ink);border:1px solid var(--line);display:flex}.links a[data-v-8bb1d4ae]:focus-visible,.links a[data-v-8bb1d4ae]:hover{border-color:var(--line-strong)}.links[data-v-8bb1d4ae] .mark,.links[data-v-8bb1d4ae] .rf-mark{width:1.35rem;height:1.35rem;color:var(--dim);flex:none;margin-top:.1rem}.links a[data-v-8bb1d4ae]:hover .mark,.links a[data-v-8bb1d4ae]:hover .rf-mark{color:var(--red)}.links span[data-v-8bb1d4ae]{flex-direction:column;gap:2px;min-width:0;display:flex}.links b[data-v-8bb1d4ae]{font-family:var(--font-display);font-size:.85rem;font-weight:400}.links small[data-v-8bb1d4ae]{color:var(--faint);font-size:.78rem}.colophon[data-v-8bb1d4ae]{color:var(--faint);margin:0;font-size:.75rem}@supports (corner-shape:bevel){.links a[data-v-8bb1d4ae]{corner-shape:bevel}}",{"innerHTML":570},".mark[data-v-cc0d96a5]{vertical-align:-.125em;flex:none;width:1em;height:1em}",{"innerHTML":572},".mark[data-v-26f5673d]{vertical-align:-.125em;flex:none;width:1em;height:1em}",{"innerHTML":574},".rf-mark[data-v-26317b3e]{fill:currentColor;stroke:none;flex:none}",1787172949832]