[{"data":1,"prerenderedAt":639},["ShallowReactive",2],{"SiteFooter_cLEacilcm59lTjFJjLY6mXNWLL0ETtzOIiZwIHgDpy0":3,"doc-\u002Fdocs\u002Foperations\u002Fdocker-images":17,"docs-nav":547,"nav-compare":619,"editor-nhzw0v":629,"editor-1h24xke":631,"editor-vhhwzc":633,"editor-1pqhtnr":635,"editor-ioua9x":637},["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":539,"extension":540,"meta":541,"navigation":67,"order":77,"path":542,"section":543,"seo":544,"stem":545,"__hash__":546},"docs\u002Fdocs\u002Foperations\u002Fdocker-images.md","Building your own image",{"type":21,"value":22,"toc":532},"minimark",[23,27,39,44,87,101,111,157,161,164,169,176,180,183,191,204,221,227,241,244,251,269,282,286,298,451,466,470,482,525,528],[24,25,26],"p",{},"The published image runs a plain Robot Framework suite. As soon as your suite\nimports another library, needs a driver, or wants a specific Python version, you\nneed an image of your own.",[24,28,29,30,34,35,38],{},"The good news is that it is a handful of lines — the published image already\nruns as ",[31,32,33],"code",{},"pwuser",", so the ",[31,36,37],{},"USER"," line below is only insurance. The thing to be careful\nabout is the version lock described further down — it is the one way to build an\nimage that looks fine and fails at runtime.",[40,41,43],"h2",{"id":42},"add-your-dependencies","Add your dependencies",[45,46,52],"pre",{"className":47,"code":48,"filename":49,"language":50,"meta":51,"style":51},"language-dockerfile shiki shiki-themes github-light github-dark","FROM marketsquare\u002Frobotframework-browser:%%browser%%\n\nUSER pwuser\nCOPY --chown=pwuser requirements.txt \u002Fhome\u002Fpwuser\u002F\nRUN pip install --no-cache-dir -r \u002Fhome\u002Fpwuser\u002Frequirements.txt\n","Dockerfile","dockerfile","",[31,53,54,62,69,75,81],{"__ignoreMap":51},[55,56,59],"span",{"class":57,"line":58},"line",1,[55,60,61],{},"FROM marketsquare\u002Frobotframework-browser:%%browser%%\n",[55,63,65],{"class":57,"line":64},2,[55,66,68],{"emptyLinePlaceholder":67},true,"\n",[55,70,72],{"class":57,"line":71},3,[55,73,74],{},"USER pwuser\n",[55,76,78],{"class":57,"line":77},4,[55,79,80],{},"COPY --chown=pwuser requirements.txt \u002Fhome\u002Fpwuser\u002F\n",[55,82,84],{"class":57,"line":83},5,[55,85,86],{},"RUN pip install --no-cache-dir -r \u002Fhome\u002Fpwuser\u002Frequirements.txt\n",[24,88,89,92,93,96,97,100],{},[31,90,91],{},"pip"," resolves to the virtualenv at ",[31,94,95],{},"\u002Fhome\u002Fpwuser\u002F.venv",", which is already on\n",[31,98,99],{},"PATH",", so there is no activation step.",[24,102,103,104,107,108,110],{},"Pin the base image to an exact release, not ",[31,105,106],{},"latest",". A pipeline that rebuilds\nweekly against ",[31,109,106],{}," will one day upgrade Browser under you, and the failure\nwill arrive on a day when nothing in your repository changed.",[112,113,115,118,142],"doc-note",{"kind":114},"warning",[24,116,117],{},"If a step needs root — installing a system package, say — switch back\nafterwards:",[45,119,121],{"className":47,"code":120,"language":50,"meta":51,"style":51},"USER root\nRUN apt-get update && apt-get install -y --no-install-recommends your-package \\\n    && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\nUSER pwuser\n",[31,122,123,128,133,138],{"__ignoreMap":51},[55,124,125],{"class":57,"line":58},[55,126,127],{},"USER root\n",[55,129,130],{"class":57,"line":64},[55,131,132],{},"RUN apt-get update && apt-get install -y --no-install-recommends your-package \\\n",[55,134,135],{"class":57,"line":71},[55,136,137],{},"    && rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\n",[55,139,140],{"class":57,"line":77},[55,141,74],{},[24,143,144,145,147,148,150,151,156],{},"Keep ",[31,146,33],{}," as the final ",[31,149,37],{},". The image's dependencies and caches are set\nup for that user, and running as root or any other user causes problems. See\n",[152,153,155],"a",{"href":154},"\u002Fdocs\u002Foperations\u002Fdocker","Running in Docker",".",[40,158,160],{"id":159},"bake-your-suite-in-or-mount-it","Bake your suite in, or mount it?",[24,162,163],{},"Both are legitimate and they answer different questions.",[165,166],"doc-table",{":head":167,":rows":168},"[\"\",\"Mount at run time\",\"`COPY` into the image\"]","[[\"How\",\"`-v $(pwd)\u002Ftests:\u002Ftest`\",\"`COPY tests \u002Fhome\u002Fpwuser\u002Ftests`\"],[\"Edit-run cycle\",\"Instant — no rebuild\",\"Rebuild per change\"],[\"What the image is\",\"A runtime\",\"A versioned artifact of *this* suite\"],[\"Best for\",\"Local development, and CI that checks the repo out anyway\",\"Shipping a suite to somewhere that does not have your repository\"]]",[24,170,171,172,175],{},"Mounting is the right default. Reach for ",[31,173,174],{},"COPY"," when the image itself has to be\nthe deliverable — a smoke test handed to an ops team, for instance.",[40,177,179],{"id":178},"the-version-lock","The version lock",[24,181,182],{},"This is the part that bites.",[24,184,185,186,190],{},"Browser is built against ",[187,188,189],"strong",{},"one specific Playwright version",", and the browser\nbinaries in the base image are the ones that Playwright version ships. Three\nthings must agree:",[192,193,194,198,201],"ol",{},[195,196,197],"li",{},"the Browser library,",[195,199,200],{},"the Playwright npm package Browser installs,",[195,202,203],{},"the browser binaries baked into the image.",[24,205,206,207,212,213,216,217,220],{},"The published image gets this right by construction: it starts from\n",[208,209],"ver",{"name":210,":code":211},"playwrightDockerImage","true",", and the Browser release it installs is\nbuilt against Playwright ",[208,214],{"name":215},"playwrightBundled",". Those two can differ by\na patch — the\n",[31,218,219],{},"FROM"," line is bumped by hand — so if you are chasing a binary-level mismatch,\ncompare them rather than assuming they agree.",[24,222,223,226],{},[187,224,225],{},"Upgrading Browser inside a derived image breaks that."," This looks harmless and\nis not:",[45,228,230],{"className":47,"code":229,"language":50,"meta":51,"style":51},"FROM marketsquare\u002Frobotframework-browser:%%browser%%\nRUN pip install --upgrade robotframework-browser   # don't\n",[31,231,232,236],{"__ignoreMap":51},[55,233,234],{"class":57,"line":58},[55,235,61],{},[55,237,238],{"class":57,"line":64},[55,239,240],{},"RUN pip install --upgrade robotframework-browser   # don't\n",[24,242,243],{},"You now have a newer Browser expecting a newer Playwright, driving the browser\nbinaries of the older one. What happens next depends on how far apart they are —\nwhich is worse than failing outright, because it can work for months and then\nnot.",[24,245,246,247,250],{},"To move to a newer Browser, ",[187,248,249],{},"change the base image tag",". That is the entire\nupgrade procedure, and it is the reason the tag exists.",[24,252,253,254,257,258,261,262,265,266,268],{},"If you genuinely must install a different Browser version in the same image, you\nown the whole chain: reinstall the Node side and let it fetch matching binaries\n(",[31,255,256],{},"rfbrowser clean-node && rfbrowser init",", which downloads a second, matching browser set — into the library's\n",[31,259,260],{},"node_modules"," when ",[31,263,264],{},"PLAYWRIGHT_BROWSERS_PATH"," is unset, otherwise wherever it\npoints, which in this base image is Playwright's own directory — while the base\nimage's binaries stay on disk, so you pay for both), or install browsers separately and\npoint ",[31,267,264],{}," at them. Both give up what the image was for.",[112,270,271],{},[24,272,273,274,277,278,281],{},"Verify with ",[31,275,276],{},"rfbrowser --version",": it prints the Browser library, Robot Framework\nand Playwright npm versions. It does ",[187,279,280],{},"not"," report the browser binaries, so it\ncannot detect a base-image mismatch on its own, and it always exits 0 — running\nit as a build step records the versions in the log rather than catching\nanything.",[40,283,285],{"id":284},"as-a-ci-job-container","As a CI job container",[24,287,288,289,293,294,297],{},"Most CI systems can run a job ",[290,291,292],"em",{},"inside"," an image, which removes the ",[31,295,296],{},"docker run","\nline entirely — your steps execute in the container, and the checkout is already\nthere.",[45,299,304],{"className":300,"code":301,"filename":302,"language":303,"meta":51,"style":51},"language-yaml shiki shiki-themes github-light github-dark","jobs:\n  robot:\n    runs-on: ubuntu-latest\n    container:\n      image: marketsquare\u002Frobotframework-browser:%%browser%%\n      options: --ipc=host --user pwuser\n    steps:\n      - uses: actions\u002Fcheckout@v7\n      - run: robot --outputdir output tests\u002F\n      - uses: actions\u002Fupload-artifact@v7\n        if: always()\n        with:\n          name: robot-results\n          path: output\u002F\n",".github\u002Fworkflows\u002Ftests.yml","yaml",[31,305,306,316,323,335,342,352,363,371,385,398,410,421,429,440],{"__ignoreMap":51},[55,307,308,312],{"class":57,"line":58},[55,309,311],{"class":310},"s9eBZ","jobs",[55,313,315],{"class":314},"sVt8B",":\n",[55,317,318,321],{"class":57,"line":64},[55,319,320],{"class":310},"  robot",[55,322,315],{"class":314},[55,324,325,328,331],{"class":57,"line":71},[55,326,327],{"class":310},"    runs-on",[55,329,330],{"class":314},": ",[55,332,334],{"class":333},"sZZnC","ubuntu-latest\n",[55,336,337,340],{"class":57,"line":77},[55,338,339],{"class":310},"    container",[55,341,315],{"class":314},[55,343,344,347,349],{"class":57,"line":83},[55,345,346],{"class":310},"      image",[55,348,330],{"class":314},[55,350,351],{"class":333},"marketsquare\u002Frobotframework-browser:%%browser%%\n",[55,353,355,358,360],{"class":57,"line":354},6,[55,356,357],{"class":310},"      options",[55,359,330],{"class":314},[55,361,362],{"class":333},"--ipc=host --user pwuser\n",[55,364,366,369],{"class":57,"line":365},7,[55,367,368],{"class":310},"    steps",[55,370,315],{"class":314},[55,372,374,377,380,382],{"class":57,"line":373},8,[55,375,376],{"class":314},"      - ",[55,378,379],{"class":310},"uses",[55,381,330],{"class":314},[55,383,384],{"class":333},"actions\u002Fcheckout@v7\n",[55,386,388,390,393,395],{"class":57,"line":387},9,[55,389,376],{"class":314},[55,391,392],{"class":310},"run",[55,394,330],{"class":314},[55,396,397],{"class":333},"robot --outputdir output tests\u002F\n",[55,399,401,403,405,407],{"class":57,"line":400},10,[55,402,376],{"class":314},[55,404,379],{"class":310},[55,406,330],{"class":314},[55,408,409],{"class":333},"actions\u002Fupload-artifact@v7\n",[55,411,413,416,418],{"class":57,"line":412},11,[55,414,415],{"class":310},"        if",[55,417,330],{"class":314},[55,419,420],{"class":333},"always()\n",[55,422,424,427],{"class":57,"line":423},12,[55,425,426],{"class":310},"        with",[55,428,315],{"class":314},[55,430,432,435,437],{"class":57,"line":431},13,[55,433,434],{"class":310},"          name",[55,436,330],{"class":314},[55,438,439],{"class":333},"robot-results\n",[55,441,443,446,448],{"class":57,"line":442},14,[55,444,445],{"class":310},"          path",[55,447,330],{"class":314},[55,449,450],{"class":333},"output\u002F\n",[24,452,453,454,457,458,461,462,465],{},"Two details are load-bearing. ",[31,455,456],{},"--ipc=host"," and ",[31,459,460],{},"--user pwuser"," still apply — a job\ncontainer gets no flags you do not give it. And ",[31,463,464],{},"if: always()"," on the upload:\nwithout it the results are discarded on exactly the runs where you needed them.",[40,467,469],{"id":468},"building-the-official-image-yourself","Building the official image yourself",[24,471,472,473,481],{},"The Dockerfiles live in\n",[152,474,478],{"href":475,"rel":476},"https:\u002F\u002Fgithub.com\u002FMarketSquare\u002Frobotframework-browser\u002Ftree\u002Fmain\u002Fdocker",[477],"nofollow",[31,479,480],{},"docker\u002F","\nin the library repository, and the same directory's README documents the local\nbuild and the pull-request image. Reach for it if you need to reproduce the\nofficial image with a change — a different Python version, a different base — or\nif you are contributing to Browser itself.",[45,483,487],{"className":484,"code":485,"language":486,"meta":51,"style":51},"language-bash shiki shiki-themes github-light github-dark","cd docker\ndocker build --no-cache -t my-rfbrowser --file Dockerfile.latest_release .\n","bash",[31,488,489,498],{"__ignoreMap":51},[55,490,491,495],{"class":57,"line":58},[55,492,494],{"class":493},"sj4cs","cd",[55,496,497],{"class":333}," docker\n",[55,499,500,504,507,510,513,516,519,522],{"class":57,"line":64},[55,501,503],{"class":502},"sScJk","docker",[55,505,506],{"class":333}," build",[55,508,509],{"class":493}," --no-cache",[55,511,512],{"class":493}," -t",[55,514,515],{"class":333}," my-rfbrowser",[55,517,518],{"class":493}," --file",[55,520,521],{"class":333}," Dockerfile.latest_release",[55,523,524],{"class":333}," .\n",[24,526,527],{},"For anything short of that, extending the published image is less work and stays\ncorrect through upgrades.",[529,530,531],"style",{},"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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":51,"searchDepth":64,"depth":64,"links":533},[534,535,536,537,538],{"id":42,"depth":64,"text":43},{"id":159,"depth":64,"text":160},{"id":178,"depth":64,"text":179},{"id":284,"depth":64,"text":285},{"id":468,"depth":64,"text":469},"Extending the published image with your dependencies, the version lock between Browser and Playwright, and using it as a CI job container.","md",{},"\u002Fdocs\u002Foperations\u002Fdocker-images","operations",{"title":19,"description":539},"docs\u002Foperations\u002Fdocker-images","KgOjtc2fQGzaMhiAAd-d0sliHmf5DyppC5Mk5rwSYVw",[548,553,557,561,565,569,573,578,582,586,590,595,599,603,605,606,610,614],{"path":549,"title":550,"description":551,"section":552,"order":83},"\u002Fdocs\u002Fconcepts\u002Farchitecture","How Browser works","Python, a Node process and Playwright — what runs where, and which installation to choose.","concepts",{"path":554,"title":555,"description":556,"section":552,"order":71},"\u002Fdocs\u002Fconcepts\u002Fassertions","Assertions","Almost every getter can assert, every assertion retries, and each return type allows different operators. The complete AssertionEngine reference.",{"path":558,"title":559,"description":560,"section":552,"order":58},"\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":562,"title":563,"description":564,"section":552,"order":354},"\u002Fdocs\u002Fconcepts\u002Flogging","Logging and debugging","Four places Browser tells you what happened — log.html, the Playwright log, traces and coverage.",{"path":566,"title":567,"description":568,"section":552,"order":64},"\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":570,"title":571,"description":572,"section":552,"order":77},"\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":574,"title":575,"description":576,"section":577,"order":64},"\u002Fdocs\u002Fextending\u002Fjavascript-basics","Just enough JavaScript","The JavaScript you need to write extensions and Evaluate JavaScript, for people who write Python.","extending",{"path":579,"title":580,"description":581,"section":577,"order":71},"\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":583,"title":584,"description":585,"section":577,"order":58},"\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":587,"title":588,"description":589,"section":577,"order":77},"\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":591,"title":592,"description":593,"section":594,"order":64},"\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":596,"title":597,"description":598,"section":594,"order":58},"\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":600,"title":601,"description":602,"section":594,"order":71},"\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":154,"title":155,"description":604,"section":543,"order":71},"The published Browser image, the four docker run flags that matter, and why running as root breaks Chromium.",{"path":542,"title":19,"description":539,"section":543,"order":77},{"path":607,"title":608,"description":609,"section":543,"order":64},"\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":611,"title":612,"description":613,"section":543,"order":58},"\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":615,"title":616,"description":617,"section":618,"order":58},"\u002Fdocs\u002Fstart\u002Fgetting-started","Getting started","Install Browser, write a first test, and run it.","start",[620,623,626],{"to":621,"label":622},"\u002Fwhy\u002Fvs-cypress","vs Cypress",{"to":624,"label":625},"\u002Fwhy\u002Fvs-playwright","vs Playwright Test",{"to":627,"label":628},"\u002Fwhy\u002Fvs-seleniumlibrary","vs SeleniumLibrary",[630],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">FROM\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> marketsquare\u002Frobotframework-browser:20.3.0\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">USER\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> pwuser\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">COPY\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> --chown=pwuser requirements.txt \u002Fhome\u002Fpwuser\u002F\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">RUN\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> pip install --no-cache-dir -r \u002Fhome\u002Fpwuser\u002Frequirements.txt\u003C\u002Fspan>\u003C\u002Fspan>",[632],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">USER\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> root\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">RUN\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> apt-get update &#x26;&#x26; apt-get install -y --no-install-recommends your-package \\\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E2E1D7\">    &#x26;&#x26; rm -rf \u002Fvar\u002Flib\u002Fapt\u002Flists\u002F*\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">USER\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> pwuser\u003C\u002Fspan>\u003C\u002Fspan>",[634],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">FROM\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> marketsquare\u002Frobotframework-browser:20.3.0\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#C9A6E9\">RUN\u003C\u002Fspan>\u003Cspan style=\"color:#E2E1D7\"> pip install --upgrade robotframework-browser   # don\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\">'t\u003C\u002Fspan>\u003C\u002Fspan>",[636],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">jobs\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">  robot\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">    runs-on\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> ubuntu-latest\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">    container\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">      image\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> marketsquare\u002Frobotframework-browser:20.3.0\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">      options\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> --ipc=host --user pwuser\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">    steps\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">      -\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> uses\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> actions\u002Fcheckout@v7\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">      -\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> run\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> robot --outputdir output tests\u002F\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#A9B4BA\">      -\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> uses\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> actions\u002Fupload-artifact@v7\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">        if\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> always()\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">        with\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">          name\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> robot-results\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E0D3A3\">          path\u003C\u002Fspan>\u003Cspan style=\"color:#A9B4BA\">:\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> output\u002F\u003C\u002Fspan>\u003C\u002Fspan>",[638],"\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">cd\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> docker\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan class=\"line\">\u003Cspan style=\"color:#2BD9CC\">docker\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> build\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> --no-cache\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> -t\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> my-rfbrowser\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> --file\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> Dockerfile.latest_release\u003C\u002Fspan>\u003Cspan style=\"color:#E0D3A3\"> .\u003C\u002Fspan>\u003C\u002Fspan>",1786734140683]