[{"data":1,"prerenderedAt":1028},["ShallowReactive",2],{"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0":3,"doc-\u002Fdocs\u002Fextending\u002Fjavascript-basics":17,"docs-nav":922,"nav-compare":996,"editor-19kqcmr":1006,"editor-z6mxxr":1008,"editor-wyuiqc":1010,"editor-rrynxc":1012,"editor-8q07vm":1014,"editor-1c2hb75":1016,"editor-1fmcdno":1018,"editor-jaoumk":1020,"editor-23jzyz":1022,"editor-qy807":1024,"editor-9vmkr":1026},["Island",4],{"key":5,"result":6},"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0",{"head":7},{"style":8},[9,11,13,15],{"innerHTML":10},".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":12},".mark[data-v-cc0d96a5]{vertical-align:-.125em;flex:none;width:1em;height:1em}",{"innerHTML":14},".mark[data-v-26f5673d]{vertical-align:-.125em;flex:none;width:1em;height:1em}",{"innerHTML":16},".rf-mark[data-v-26317b3e]{fill:currentColor;stroke:none;flex:none}",{"id":18,"title":19,"body":20,"description":914,"extension":915,"meta":916,"navigation":283,"order":92,"path":917,"section":918,"seo":919,"stem":920,"__hash__":921},"docs\u002Fdocs\u002Fextending\u002Fjavascript-basics.md","Just enough JavaScript",{"type":21,"value":22,"toc":904},"minimark",[23,27,32,35,40,53,57,126,135,139,149,178,182,185,216,222,226,346,349,387,391,394,478,497,574,588,592,595,656,666,684,688,691,694,733,770,773,810,817,820,861,900],[24,25,26],"p",{},"You do not need to know JavaScript to use Browser. You need a little to extend\nit. This page is the little.",[28,29,31],"h2",{"id":30},"two-different-javascripts","Two different JavaScripts",[24,33,34],{},"The most common confusion, and worth getting straight first:",[36,37],"doc-table",{":head":38,":rows":39},"[\"Where it runs\",\"What exists there\",\"Reached by\"]","[[\"Node.js\",\"Playwright, `page`, the filesystem\",\"A JS extension module\"],[\"The browser page\",\"`document`, `window`, the DOM\",\"`Evaluate JavaScript`, `page.evaluate`\"]]",[24,41,42,43,47,48,52],{},"Node-side code drives the browser. Page-side code runs ",[44,45,46],"em",{},"inside"," it. ",[49,50,51],"code",{},"document","\ndoes not exist in Node; Playwright does not exist in the page.",[28,54,56],{"id":55},"variables","Variables",[58,59,64],"pre",{"className":60,"code":61,"language":62,"meta":63,"style":63},"language-javascript shiki shiki-themes github-light github-dark","let count = 2      \u002F\u002F block scoped, reassignable\nconst name = 'x'   \u002F\u002F block scoped, not reassignable\nvar old = 1        \u002F\u002F function scoped — avoid\n","javascript","",[49,65,66,90,109],{"__ignoreMap":63},[67,68,71,75,79,82,86],"span",{"class":69,"line":70},"line",1,[67,72,74],{"class":73},"szBVR","let",[67,76,78],{"class":77},"sVt8B"," count ",[67,80,81],{"class":73},"=",[67,83,85],{"class":84},"sj4cs"," 2",[67,87,89],{"class":88},"sJ8bj","      \u002F\u002F block scoped, reassignable\n",[67,91,93,96,99,102,106],{"class":69,"line":92},2,[67,94,95],{"class":73},"const",[67,97,98],{"class":84}," name",[67,100,101],{"class":73}," =",[67,103,105],{"class":104},"sZZnC"," 'x'",[67,107,108],{"class":88},"   \u002F\u002F block scoped, not reassignable\n",[67,110,112,115,118,120,123],{"class":69,"line":111},3,[67,113,114],{"class":73},"var",[67,116,117],{"class":77}," old ",[67,119,81],{"class":73},[67,121,122],{"class":84}," 1",[67,124,125],{"class":88},"        \u002F\u002F function scoped — avoid\n",[24,127,128,129,131,132,134],{},"Use ",[49,130,95],{}," by default and ",[49,133,74],{}," when you must reassign.",[28,136,138],{"id":137},"strings","Strings",[24,140,141,144,145,148],{},[49,142,143],{},"'single'"," and ",[49,146,147],{},"\"double\""," are the same. Backticks interpolate:",[58,150,152],{"className":60,"code":151,"language":62,"meta":63,"style":63},"const greeting = `Hello ${name}, you have ${count} items`\n",[49,153,154],{"__ignoreMap":63},[67,155,156,158,161,163,166,169,172,175],{"class":69,"line":70},[67,157,95],{"class":73},[67,159,160],{"class":84}," greeting",[67,162,101],{"class":73},[67,164,165],{"class":104}," `Hello ${",[67,167,168],{"class":77},"name",[67,170,171],{"class":104},"}, you have ${",[67,173,174],{"class":77},"count",[67,176,177],{"class":104},"} items`\n",[28,179,181],{"id":180},"equality","Equality",[24,183,184],{},"The one that catches Python developers:",[58,186,188],{"className":60,"code":187,"language":62,"meta":63,"style":63},"\"32\" == 32     \u002F\u002F true  — coerces types\n\"32\" === 32    \u002F\u002F false — compares type as well\n",[49,189,190,204],{"__ignoreMap":63},[67,191,192,195,198,201],{"class":69,"line":70},[67,193,194],{"class":104},"\"32\"",[67,196,197],{"class":73}," ==",[67,199,200],{"class":84}," 32",[67,202,203],{"class":88},"     \u002F\u002F true  — coerces types\n",[67,205,206,208,211,213],{"class":69,"line":92},[67,207,194],{"class":104},[67,209,210],{"class":73}," ===",[67,212,200],{"class":84},[67,214,215],{"class":88},"    \u002F\u002F false — compares type as well\n",[24,217,128,218,221],{},[49,219,220],{},"===",". Always.",[28,223,225],{"id":224},"functions-and-arrow-functions","Functions and arrow functions",[58,227,229],{"className":60,"code":228,"language":62,"meta":63,"style":63},"function add(a, b) {\n  return a + b\n}                                  \u002F\u002F can be called before it is defined\n\nconst sum = (a, b) => a + b        \u002F\u002F must be defined before use\nconst double = a => a + a          \u002F\u002F one expression: no braces, no return\n",[49,230,231,256,270,278,285,320],{"__ignoreMap":63},[67,232,233,236,240,243,247,250,253],{"class":69,"line":70},[67,234,235],{"class":73},"function",[67,237,239],{"class":238},"sScJk"," add",[67,241,242],{"class":77},"(",[67,244,246],{"class":245},"s4XuR","a",[67,248,249],{"class":77},", ",[67,251,252],{"class":245},"b",[67,254,255],{"class":77},") {\n",[67,257,258,261,264,267],{"class":69,"line":92},[67,259,260],{"class":73},"  return",[67,262,263],{"class":77}," a ",[67,265,266],{"class":73},"+",[67,268,269],{"class":77}," b\n",[67,271,272,275],{"class":69,"line":111},[67,273,274],{"class":77},"}                                  ",[67,276,277],{"class":88},"\u002F\u002F can be called before it is defined\n",[67,279,281],{"class":69,"line":280},4,[67,282,284],{"emptyLinePlaceholder":283},true,"\n",[67,286,288,290,293,295,298,300,302,304,307,310,312,314,317],{"class":69,"line":287},5,[67,289,95],{"class":73},[67,291,292],{"class":238}," sum",[67,294,101],{"class":73},[67,296,297],{"class":77}," (",[67,299,246],{"class":245},[67,301,249],{"class":77},[67,303,252],{"class":245},[67,305,306],{"class":77},") ",[67,308,309],{"class":73},"=>",[67,311,263],{"class":77},[67,313,266],{"class":73},[67,315,316],{"class":77}," b        ",[67,318,319],{"class":88},"\u002F\u002F must be defined before use\n",[67,321,323,325,328,330,333,336,338,340,343],{"class":69,"line":322},6,[67,324,95],{"class":73},[67,326,327],{"class":238}," double",[67,329,101],{"class":73},[67,331,332],{"class":245}," a",[67,334,335],{"class":73}," =>",[67,337,263],{"class":77},[67,339,266],{"class":73},[67,341,342],{"class":77}," a          ",[67,344,345],{"class":88},"\u002F\u002F one expression: no braces, no return\n",[24,347,348],{},"Arrow functions are what you will mostly write, because callbacks are\neverywhere:",[58,350,352],{"className":60,"code":351,"language":62,"meta":63,"style":63},"const odds = numbers.filter(n => n % 2)\n",[49,353,354],{"__ignoreMap":63},[67,355,356,358,361,363,366,369,371,374,376,379,382,384],{"class":69,"line":70},[67,357,95],{"class":73},[67,359,360],{"class":84}," odds",[67,362,101],{"class":73},[67,364,365],{"class":77}," numbers.",[67,367,368],{"class":238},"filter",[67,370,242],{"class":77},[67,372,373],{"class":245},"n",[67,375,335],{"class":73},[67,377,378],{"class":77}," n ",[67,380,381],{"class":73},"%",[67,383,85],{"class":84},[67,385,386],{"class":77},")\n",[28,388,390],{"id":389},"objects-and-arrays","Objects and arrays",[24,392,393],{},"A JS object is close to a Python dict, with unquoted keys:",[58,395,397],{"className":60,"code":396,"language":62,"meta":63,"style":63},"const obj = { key: 'test', list: [1, 2, 3], nested: { subKey: 'test' } }\nconst asText = JSON.stringify(obj)\nconst back = JSON.parse(asText)\n",[49,398,399,438,459],{"__ignoreMap":63},[67,400,401,403,406,408,411,414,417,420,422,425,427,430,433,435],{"class":69,"line":70},[67,402,95],{"class":73},[67,404,405],{"class":84}," obj",[67,407,101],{"class":73},[67,409,410],{"class":77}," { key: ",[67,412,413],{"class":104},"'test'",[67,415,416],{"class":77},", list: [",[67,418,419],{"class":84},"1",[67,421,249],{"class":77},[67,423,424],{"class":84},"2",[67,426,249],{"class":77},[67,428,429],{"class":84},"3",[67,431,432],{"class":77},"], nested: { subKey: ",[67,434,413],{"class":104},[67,436,437],{"class":77}," } }\n",[67,439,440,442,445,447,450,453,456],{"class":69,"line":92},[67,441,95],{"class":73},[67,443,444],{"class":84}," asText",[67,446,101],{"class":73},[67,448,449],{"class":84}," JSON",[67,451,452],{"class":77},".",[67,454,455],{"class":238},"stringify",[67,457,458],{"class":77},"(obj)\n",[67,460,461,463,466,468,470,472,475],{"class":69,"line":111},[67,462,95],{"class":73},[67,464,465],{"class":84}," back",[67,467,101],{"class":73},[67,469,449],{"class":84},[67,471,452],{"class":77},[67,473,474],{"class":238},"parse",[67,476,477],{"class":77},"(asText)\n",[24,479,480,481,249,484,249,486,249,489,492,493,496],{},"Arrays have the methods you want — ",[49,482,483],{},"map",[49,485,368],{},[49,487,488],{},"forEach",[49,490,491],{},"find",". But many\nDOM results are ",[44,494,495],{},"iterable"," without being arrays, so convert first:",[58,498,500],{"className":60,"code":499,"language":62,"meta":63,"style":63},"const inputs = Array.from(document.querySelectorAll('input'))\nconst values = inputs.filter(e => e.type === 'text').map(e => e.value)\n",[49,501,502,531],{"__ignoreMap":63},[67,503,504,506,509,511,514,517,520,523,525,528],{"class":69,"line":70},[67,505,95],{"class":73},[67,507,508],{"class":84}," inputs",[67,510,101],{"class":73},[67,512,513],{"class":77}," Array.",[67,515,516],{"class":238},"from",[67,518,519],{"class":77},"(document.",[67,521,522],{"class":238},"querySelectorAll",[67,524,242],{"class":77},[67,526,527],{"class":104},"'input'",[67,529,530],{"class":77},"))\n",[67,532,533,535,538,540,543,545,547,550,552,555,557,560,563,565,567,569,571],{"class":69,"line":92},[67,534,95],{"class":73},[67,536,537],{"class":84}," values",[67,539,101],{"class":73},[67,541,542],{"class":77}," inputs.",[67,544,368],{"class":238},[67,546,242],{"class":77},[67,548,549],{"class":245},"e",[67,551,335],{"class":73},[67,553,554],{"class":77}," e.type ",[67,556,220],{"class":73},[67,558,559],{"class":104}," 'text'",[67,561,562],{"class":77},").",[67,564,483],{"class":238},[67,566,242],{"class":77},[67,568,549],{"class":245},[67,570,335],{"class":73},[67,572,573],{"class":77}," e.value)\n",[24,575,576,577,580,581,584,585,452],{},"Forgetting ",[49,578,579],{},"Array.from"," is the single most common mistake here:\n",[49,582,583],{},"document.querySelectorAll(...)"," has no ",[49,586,587],{},".map",[28,589,591],{"id":590},"async-and-await","async and await",[24,593,594],{},"Almost every Playwright call is asynchronous:",[58,596,598],{"className":60,"code":597,"language":62,"meta":63,"style":63},"async function getTitle(page) {\n  await page.goto('https:\u002F\u002Fexample.com')\n  return await page.title()\n}\n",[49,599,600,618,636,651],{"__ignoreMap":63},[67,601,602,605,608,611,613,616],{"class":69,"line":70},[67,603,604],{"class":73},"async",[67,606,607],{"class":73}," function",[67,609,610],{"class":238}," getTitle",[67,612,242],{"class":77},[67,614,615],{"class":245},"page",[67,617,255],{"class":77},[67,619,620,623,626,629,631,634],{"class":69,"line":92},[67,621,622],{"class":73},"  await",[67,624,625],{"class":77}," page.",[67,627,628],{"class":238},"goto",[67,630,242],{"class":77},[67,632,633],{"class":104},"'https:\u002F\u002Fexample.com'",[67,635,386],{"class":77},[67,637,638,640,643,645,648],{"class":69,"line":111},[67,639,260],{"class":73},[67,641,642],{"class":73}," await",[67,644,625],{"class":77},[67,646,647],{"class":238},"title",[67,649,650],{"class":77},"()\n",[67,652,653],{"class":69,"line":280},[67,654,655],{"class":77},"}\n",[24,657,658,659,661,662,665],{},"An ",[49,660,604],{}," function returns a promise. ",[49,663,664],{},"await"," waits for one.",[24,667,668,669,672,673,676,677,680,681,683],{},"Browser awaits whatever your keyword returns, so a promise returned ",[44,670,671],{},"directly","\nresolves fine. A promise tucked ",[674,675,46],"strong",{}," the returned value does not — it is\nserialised as ",[49,678,679],{},"{}",". If one field of your result comes back empty, a missing\n",[49,682,664],{}," is usually why.",[28,685,687],{"id":686},"evaluate-javascript","Evaluate JavaScript",[24,689,690],{},"You can run page-side JavaScript from Robot Framework directly, which is often\nenough without writing an extension at all.",[24,692,693],{},"Three things about its shape, because they are what people get wrong first:",[695,696,697,709,727],"ul",{},[698,699,700,701,704,705,708],"li",{},"The ",[674,702,703],{},"first argument is a selector",", and it cannot be omitted — pass\n",[49,706,707],{},"${None}"," when you do not want one.",[698,710,711,712,715,716,719,720,723,724,452],{},"With a selector, the function receives ",[49,713,714],{},"(element, arg)","; with ",[49,717,718],{},"all_elements=True","\nit receives ",[49,721,722],{},"(elements, arg)"," — that flag is what makes it an array. With no\nselector it receives just ",[49,725,726],{},"(arg)",[698,728,729,730,452],{},"The return value must be JSON-serialisable. Returning nothing gives you an\nempty string, and a DOM node comes back as the useless string ",[49,731,732],{},"ref: \u003CNode>",[58,734,738],{"className":735,"code":736,"language":737,"meta":63,"style":63},"language-robot shiki shiki-themes github-light github-dark","*** Test Cases ***\nCollect Every Link Text\n    ${texts} =    Evaluate JavaScript    a\n    ...    elements => elements.map(e => e.innerText).filter(text => text)\n    ...    all_elements=True\n    Log Many    @{texts}\n","robot",[49,739,740,745,750,755,760,765],{"__ignoreMap":63},[67,741,742],{"class":69,"line":70},[67,743,744],{},"*** Test Cases ***\n",[67,746,747],{"class":69,"line":92},[67,748,749],{},"Collect Every Link Text\n",[67,751,752],{"class":69,"line":111},[67,753,754],{},"    ${texts} =    Evaluate JavaScript    a\n",[67,756,757],{"class":69,"line":280},[67,758,759],{},"    ...    elements => elements.map(e => e.innerText).filter(text => text)\n",[67,761,762],{"class":69,"line":287},[67,763,764],{},"    ...    all_elements=True\n",[67,766,767],{"class":69,"line":322},[67,768,769],{},"    Log Many    @{texts}\n",[24,771,772],{},"Compare that with doing it keyword by keyword:",[58,774,778],{"className":775,"code":776,"language":777,"meta":63,"style":63},"language-robot-repl shiki shiki-themes github-light github-dark","${elements} =    Get Elements    a\n${texts} =    Create List\nFOR    ${element}    IN    @{elements}\n    ${text} =    Get Text    ${element}\n    IF    $text    Append To List    ${texts}    ${text}    # needs Library Collections\nEND\n","robot-repl",[49,779,780,785,790,795,800,805],{"__ignoreMap":63},[67,781,782],{"class":69,"line":70},[67,783,784],{},"${elements} =    Get Elements    a\n",[67,786,787],{"class":69,"line":92},[67,788,789],{},"${texts} =    Create List\n",[67,791,792],{"class":69,"line":111},[67,793,794],{},"FOR    ${element}    IN    @{elements}\n",[67,796,797],{"class":69,"line":280},[67,798,799],{},"    ${text} =    Get Text    ${element}\n",[67,801,802],{"class":69,"line":287},[67,803,804],{},"    IF    $text    Append To List    ${texts}    ${text}    # needs Library Collections\n",[67,806,807],{"class":69,"line":322},[67,808,809],{},"END\n",[24,811,812,813,816],{},"Both are correct. The first is one round trip to the browser; the second is one\nper element, plus one for ",[49,814,815],{},"Get Elements",". On a page with a hundred links, that\ndifference is visible.",[24,818,819],{},"Returning an object works too, and arrives in Robot Framework as a dictionary:",[58,821,823],{"className":775,"code":822,"language":777,"meta":63,"style":63},"${links} =    Evaluate JavaScript    a\n...    elements => {\n...        const object = {}\n...        elements.filter(e => e.innerText).forEach(e => object[e.innerText] = e.href)\n...        return object\n...    }\n...    all_elements=True\n",[49,824,825,830,835,840,845,850,855],{"__ignoreMap":63},[67,826,827],{"class":69,"line":70},[67,828,829],{},"${links} =    Evaluate JavaScript    a\n",[67,831,832],{"class":69,"line":92},[67,833,834],{},"...    elements => {\n",[67,836,837],{"class":69,"line":111},[67,838,839],{},"...        const object = {}\n",[67,841,842],{"class":69,"line":280},[67,843,844],{},"...        elements.filter(e => e.innerText).forEach(e => object[e.innerText] = e.href)\n",[67,846,847],{"class":69,"line":287},[67,848,849],{},"...        return object\n",[67,851,852],{"class":69,"line":322},[67,853,854],{},"...    }\n",[67,856,858],{"class":69,"line":857},7,[67,859,860],{},"...    all_elements=True\n",[862,863,864,877],"doc-note",{},[24,865,866,867,249,869,872,873,876],{},"Practise in your browser's devtools console before writing an extension: both run\nin the page. Browser first tries to turn the string into a function in Node; if\nthat throws — as it does for anything touching ",[49,868,51],{},[49,870,871],{},"window"," or\n",[49,874,875],{},"location"," — the raw string is passed through and evaluated in the page instead,\nso pasting a bare expression normally just works.",[24,878,879,880,883,884,887,888,891,892,895,896,899],{},"The exception is an expression Node ",[44,881,882],{},"can"," evaluate. ",[49,885,886],{},"Object.keys({a: 1})","\nbecomes the array ",[49,889,890],{},"[\"a\"]"," in Node, is stringified on the way into the page, and\nfails there with ",[49,893,894],{},"ReferenceError: a is not defined",". Wrapping what you paste in\nan arrow function, ",[49,897,898],{},"() => document.querySelectorAll('a').length",", sidesteps the\nquestion entirely.",[901,902,903],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":63,"searchDepth":92,"depth":92,"links":905},[906,907,908,909,910,911,912,913],{"id":30,"depth":92,"text":31},{"id":55,"depth":92,"text":56},{"id":137,"depth":92,"text":138},{"id":180,"depth":92,"text":181},{"id":224,"depth":92,"text":225},{"id":389,"depth":92,"text":390},{"id":590,"depth":92,"text":591},{"id":686,"depth":92,"text":687},"The JavaScript you need to write extensions and Evaluate JavaScript, for people who write Python.","md",{},"\u002Fdocs\u002Fextending\u002Fjavascript-basics","extending",{"title":19,"description":914},"docs\u002Fextending\u002Fjavascript-basics","vgBmJDHr7pamIdFIgviKiKARNPU7WGrKUjE02OvbHMw",[923,928,932,936,940,944,948,949,953,957,961,966,970,974,979,983,987,991],{"path":924,"title":925,"description":926,"section":927,"order":287},"\u002Fdocs\u002Fconcepts\u002Farchitecture","How Browser works","Python, a Node process and Playwright — what runs where, and which installation to choose.","concepts",{"path":929,"title":930,"description":931,"section":927,"order":111},"\u002Fdocs\u002Fconcepts\u002Fassertions","Assertions","Almost every getter can assert, every assertion retries, and each return type allows different operators. The complete AssertionEngine reference.",{"path":933,"title":934,"description":935,"section":927,"order":70},"\u002Fdocs\u002Fconcepts\u002Fbrowser-context-page","Browser, context and page","The three layers Playwright is built on — and why a new context is the cheapest clean slate you will ever get.",{"path":937,"title":938,"description":939,"section":927,"order":322},"\u002Fdocs\u002Fconcepts\u002Flogging","Logging and debugging","Four places Browser tells you what happened — log.html, the Playwright log, traces and coverage.",{"path":941,"title":942,"description":943,"section":927,"order":92},"\u002Fdocs\u002Fconcepts\u002Fselectors","Finding elements","Which selector strategy to reach for, why the order matters, and how to chain across iframes and shadow DOM.",{"path":945,"title":946,"description":947,"section":927,"order":280},"\u002Fdocs\u002Fconcepts\u002Fwaiting","Waiting and promises","Most waiting is already done for you. This is the rest of it — Wait For Condition, and how to run keywords in parallel with Promise To.",{"path":917,"title":19,"description":914,"section":918,"order":92},{"path":950,"title":951,"description":952,"section":918,"order":111},"\u002Fdocs\u002Fextending\u002Fjavascript-extensions","JavaScript extensions","Add keywords that run on the Node side with full Playwright access — and attach a debugger to them.",{"path":954,"title":955,"description":956,"section":918,"order":70},"\u002Fdocs\u002Fextending\u002Fpython-plugins","Python plugins","Add or replace keywords from Python, with access to the library's own API and to the Node side.",{"path":958,"title":959,"description":960,"section":918,"order":280},"\u002Fdocs\u002Fextending\u002Ftranslations","Translating keywords","Using a translation package to get keyword names and documentation in your language, and writing one for a language nobody has covered yet.",{"path":962,"title":963,"description":964,"section":965,"order":92},"\u002Fdocs\u002Fmobile\u002Fdevices","Emulating a device","Device descriptors, what the six or seven properties they set actually change, and the one that emulation cannot give you.","mobile",{"path":967,"title":968,"description":969,"section":965,"order":70},"\u002Fdocs\u002Fmobile\u002Fresponsive","Testing responsive pages","Why a browser at a phone-sized viewport tests responsiveness properly, what emulation cannot tell you, and where real devices actually belong.",{"path":971,"title":972,"description":973,"section":965,"order":111},"\u002Fdocs\u002Fmobile\u002Ftouch","Touch, permissions and location","Tap and why it needs hasTouch, granting camera or notifications without a dialog, faking where the user is, and the gestures Browser has no keyword for.",{"path":975,"title":976,"description":977,"section":978,"order":111},"\u002Fdocs\u002Foperations\u002Fdocker","Running in Docker","The published Browser image, the four docker run flags that matter, and why running as root breaks Chromium.","operations",{"path":980,"title":981,"description":982,"section":978,"order":280},"\u002Fdocs\u002Foperations\u002Fdocker-images","Building your own image","Extending the published image with your dependencies, the version lock between Browser and Playwright, and using it as a CI job container.",{"path":984,"title":985,"description":986,"section":978,"order":92},"\u002Fdocs\u002Foperations\u002Fenvironment-variables","Environment variables","The variables that change how Browser behaves, which of them are safe in production, and the import parameters that should usually be preferred.",{"path":988,"title":989,"description":990,"section":978,"order":70},"\u002Fdocs\u002Foperations\u002Fnode-process","The Node process","Browser starts a Node process to talk to Playwright. What that costs, how to share one across parallel runs, and how to pass it Node flags.",{"path":992,"title":993,"description":994,"section":995,"order":70},"\u002Fdocs\u002Fstart\u002Fgetting-started","Getting started","Install Browser, write a first test, and run it.","start",[997,1000,1003],{"to":998,"label":999},"\u002Fwhy\u002Fvs-cypress","vs Cypress",{"to":1001,"label":1002},"\u002Fwhy\u002Fvs-playwright","vs Playwright Test",{"to":1004,"label":1005},"\u002Fwhy\u002Fvs-seleniumlibrary","vs SeleniumLibrary",[1007],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">let\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> count\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 2\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">      \u002F\u002F block scoped, reassignable\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> name\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> '\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">x\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">   \u002F\u002F block scoped, not reassignable\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">var\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> old\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 1\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">        \u002F\u002F function scoped — avoid\u003C\u002Fspan>\u003C\u002Fspan>",[1009],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> greeting\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> `\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">Hello \u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">name\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">, you have \u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">count\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> items\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">`\u003C\u002Fspan>\u003C\u002Fspan>",[1011],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">32\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> ==\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 32\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">     \u002F\u002F true  — coerces types\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">32\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">\"\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> ===\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 32\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">    \u002F\u002F false — compares type as well\u003C\u002Fspan>\u003C\u002Fspan>",[1013],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">function\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> add\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\">a\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> b\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> {\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">  return\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> a\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> +\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> b\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">                                  \u002F\u002F can be called before it is defined\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> sum\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> (\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\">a\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> b\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> =>\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> a\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> +\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> b\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">        \u002F\u002F must be defined before use\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> double\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> a \u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">=>\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> a\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> +\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> a\u003C\u002Fspan>\u003Cspan style=\"color:#96A2A8;font-style:italic\">          \u002F\u002F one expression: no braces, no return\u003C\u002Fspan>\u003C\u002Fspan>",[1015],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> odds\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> numbers\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">filter\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\">n \u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">=>\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> n\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> %\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 2\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003C\u002Fspan>",[1017],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> obj\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> {\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> key\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> '\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">test\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">,\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> list\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> [\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">1\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">,\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 2\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">,\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> 3\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">],\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> nested\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> {\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> subKey\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> '\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">test\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> }\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> }\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> asText\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> JSON\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">stringify\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">obj\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> back\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> JSON\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">parse\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">asText\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003C\u002Fspan>",[1019],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> inputs\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> Array\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">from\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">document\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">querySelectorAll\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">input\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">))\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">const\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> values\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> inputs\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">filter\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\">e \u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">=>\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> e\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">type\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> ===\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> '\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">text\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">).\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">map\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\">e \u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">=>\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> e\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">value\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003C\u002Fspan>",[1021],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">async\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> function\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\"> getTitle\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\">page\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\"> {\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">  await\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> page\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">goto\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">(\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">https:\u002F\u002Fexample.com\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">'\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">)\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">  return\u003C\u002Fspan>\u003Cspan style=\"color:#C9A6E9\"> await\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\"> page\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">.\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">title\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">()\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003C\u002Fspan>",[1023],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E;font-weight:bold\">*** Test Cases ***\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">Collect Every Link Text\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">    ${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">texts\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">    Evaluate JavaScript\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    a\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">    ...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    elements => elements.map(e => e.innerText).filter(text => text)\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">    ...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    all_elements=True\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">    Log Many\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">    @{\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">texts\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003C\u002Fspan>",[1025],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">elements\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">    Get Elements\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    a\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">texts\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">    Create List\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">FOR\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">    ${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">element\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    IN    \u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">@{\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">elements\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">    ${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">text\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">    Get Text\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">    ${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">element\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">    IF\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">    $\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">text\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    Append To List    \u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">texts\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">    ${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">text\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA;font-style:italic\">    # needs Library Collections\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">END\u003C\u002Fspan>\u003C\u002Fspan>",[1027],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">${\u003C\u002Fspan>\u003Cspan style=\"color:#FFB86B\">links\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">}\u003C\u002Fspan>\u003Cspan style=\"color:#FF6B5E\"> =\u003C\u002Fspan>\u003Cspan style=\"color:#2BD9CC\">    Evaluate JavaScript\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    a\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    elements => {\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">        const object = {}\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">        elements.filter(e => e.innerText).forEach(e => object[e.innerText] = e.href)\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">        return object\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    }\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#FF6B5E\">...\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">    all_elements=True\u003C\u002Fspan>\u003C\u002Fspan>",1786734140324]