1(self.webpackChunkelemental_selenium=self.webpackChunkelemental_selenium||[]).push([[6727],{61552:(e,t,a)=>{"use strict";a.r(t),a.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"use-a-page-object/7-use-a-page-object","title":"Use A Page Object","description":"One of the biggest challenges with Selenium tests is that they can be brittle and challenging to maintain over time. This is largely due to the fact that things in the app you\'re testing change, breaking your tests.","source":"@site/tips/7-use-a-page-object/main.mdx","sourceDirName":"7-use-a-page-object","slug":"/7-use-a-page-object","permalink":"/tips/7-use-a-page-object","draft":false,"unlisted":false,"editUrl":"https://github.com/saucelabs/elemental-next/blob/main/frontend/tips/7-use-a-page-object/main.mdx","tags":[{"inline":true,"label":"page object","permalink":"/tips/tags/page-object"},{"inline":true,"label":"abstraction","permalink":"/tips/tags/abstraction"}],"version":"current","lastUpdatedBy":"Diego Molina","lastUpdatedAt":1710769270000,"frontMatter":{"title":"Use A Page Object","id":"7-use-a-page-object","slug":"/7-use-a-page-object","sidebar_label":"Use A Page Object","description":"One of the biggest challenges with Selenium tests is that they can be brittle and challenging to maintain over time. This is largely due to the fact that things in the app you\'re testing change, breaking your tests.","number":7,"hide_table_of_contents":true,"level":2,"publish_date":"2013-07-09T00:00:00.000Z","tags":["page object","abstraction"],"category":["tools"]},"sidebar":"defaultSidebar","previous":{"title":"How to Open a New Window or Tab","permalink":"/tips/6-open-new-window"},"next":{"title":"Download A File Revisited","permalink":"/tips/8-download-a-file-revisited"}}');var n=a(74848),o=a(28453),s=a(94447);const i={title:"Use A Page Object",id:"7-use-a-page-object",slug:"/7-use-a-page-object",sidebar_label:"Use A Page Object",description:"One of the biggest challenges with Selenium tests is that they can be brittle and challenging to maintain over time. This is largely due to the fact that things in the app you're testing change, breaking your tests.",number:7,hide_table_of_contents:!0,level:2,publish_date:new Date("2013-07-09T00:00:00.000Z"),tags:["page object","abstraction"],category:["tools"]},l="Using a Page Object",d={},u=[{value:"Intro",id:"intro",level:2},{value:"A Solution",id:"a-solution",level:2},{value:"About The Author",id:"about-the-author",level:2}];function c(e){const t={h1:"h1",h2:"h2",header:"header",img:"img",p:"p",...(0,o.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"using-a-page-object",children:"Using a Page Object"})}),"\n",(0,n.jsx)(t.h2,{id:"intro",children:"Intro"}),"\n",(0,n.jsx)(t.p,{children:"One of the biggest challenges with Selenium tests is that they can be brittle and challenging to maintain over time.\nThis is largely due to the fact that things in the app you're testing change, breaking your tests."}),"\n",(0,n.jsx)(t.p,{children:"But the reality of a software project is that change is a constant. So we need to account for this reality somehow\nin our test code in order to be successful."}),"\n",(0,n.jsx)(t.h2,{id:"a-solution",children:"A Solution"}),"\n",(0,n.jsx)(t.p,{children:"Enter Page Objects."}),"\n",(0,n.jsx)(t.p,{children:"Rather than write your test code directly against your app, you can model the behavior of your application into\nsimple objects -- and write your tests against them instead. That way when your app changes and your tests break,\nyou only have to update your test code in one place to fix it."}),"\n",(0,n.jsx)(t.p,{children:"And with this approach, we not only get the benefit of controlled chaos, we also get the benefit of reusable behavior."}),"\n","\n",(0,n.jsx)(s.A,{languages:[{label:"Ruby",value:"ruby"}]}),"\n",(0,n.jsx)(t.h2,{id:"about-the-author",children:"About The Author"}),"\n",(0,n.jsx)(t.p,{children:"Dave Haeffner is the original writer of Elemental Selenium -- a free, once weekly Selenium tip newsletter that's read\nby thousands of testing professionals. He also created and maintains the-internet (an open-source web app that's\nperfect for writing automated tests against)."}),"\n",(0,n.jsx)(t.p,{children:"Dave has helped numerous companies successfully implement automated acceptance testing; including The Motley Fool,\nManTech International, Sittercity, and Animoto. He is also an active member of the Selenium project and has spoken\nat numerous conferences and meetups around the world about automated acceptance testing."}),"\n",(0,n.jsx)(t.p,{children:(0,n.jsx)(t.img,{alt:"Dave Haeffner profile picture",src:a(59278).A+"#author-img",title:"a title",width:"280",height:"280"})})]})}function h(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(c,{...e})}):c(e)}},17081:(e,t,a)=>{"use strict";a.d(t,{_:()=>i,u:()=>l});var r=a(96540),n=a(26849),o=a(74848);const s=r.createContext(null);function i(e){let{children:t,content:a}=e;const n=function(e){return(0,r.useMemo)((()=>({metadata:e.metadata,frontMatter:e.frontMatter,assets:e.assets,contentTitle:e.contentTitle,toc:e.toc})),[e])}(a);return(0,o.jsx)(s.Provider,{value:n,children:t})}function l(){const e=(0,r.useContext)(s);if(null===e)throw new n.dV("DocProvider");return e}},94447:(e,t,a)=>{"use strict";a.d(t,{A:()=>T});var r=a(96540),n=a(34164),o=a(65627),s=a(56347),i=a(50372),l=a(30604),d=a(11861),u=a(78749);function c(e){return r.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,r.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs>
1 child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function h(e){const{values:t,children:a}=e;return(0,r.useMemo)((()=>{const e=t??function(e){return c(e).map((e=>{let{props:{value:t,label:a,attributes:r,default:n}}=e;return{value:t,label:a,attributes:r,default:n}}))}(a);return function(e){const t=(0,d.XI)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[t,a])}function m(e){let{value:t,tabValues:a}=e;return a.some((e=>e.value===t))}function p(e){let{queryString:t=!1,groupId:a}=e;const n=(0,s.W6)(),o=function(e){let{queryString:t=!1,groupId:a}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!a)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return a??null}({queryString:t,groupId:a});return[(0,l.aZ)(o),(0,r.useCallback)((e=>{if(!o)return;const t=new URLSearchParams(n.location.search);t.set(o,e),n.replace({...n.location,search:t.toString()})}),[o,n])]}function b(e){const{defaultValue:t,queryString:a=!1,groupId:n}=e,o=h(e),[s,l]=(0,r.useState)((()=>function(e){let{defaultValue:t,tabValues:a}=e;if(0===a.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(t){if(!m({value:t,tabValues:a}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${a.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const r=a.find((e=>e.default))??a[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:t,tabValues:o}))),[d,c]=p({queryString:a,groupId:n}),[b,x]=function(e){let{groupId:t}=e;const a=function(e){return e?`docusaurus.tab.${e}`:null}(t),[n,o]=(0,u.Dv)(a);return[n,(0,r.useCallback)((e=>{a&&o.set(e)}),[a,o])]}({groupId:n}),w=(()=>{const e=d??b;return m({value:e,tabValues:o})?e:null})();(0,i.A)((()=>{w&&l(w)}),[w]);return{selectedValue:s,selectValue:(0,r.useCallback)((e=>{if(!m({value:e,tabValues:o}))throw new Error(`Can't select invalid tab value=${e}`);l(e),c(e),x(e)}),[c,x,o]),tabValues:o}}var x=a(9136);const w={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var g=a(74848);function f(e){let{className:t,block:a,selectedValue:r,selectValue:s,tabValues:i}=e;const l=[],{blockElementScrollPositionUntilNextRender:d}=(0,o.a_)(),u=e=>{const t=e.currentTarget,a=l.indexOf(t),n=i[a].value;n!==r&&(d(t),s(n))},c=e=>{let t=null;switch(e.key){case"Enter":u(e);break;case"ArrowRight":{const a=l.indexOf(e.currentTarget)+1;t=l[a]??l[0];break}case"ArrowLeft":{const a=l.indexOf(e.currentTarget)-1;t=l[a]??l[l.length-1];break}}t?.focus()};return(0,g.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,n.A)("tabs",{"tabs--block":a},t),children:i.map((e=>{let{value:t,label:a,attributes:o}=e;return(0,g.jsx)("li",{role:"tab",tabIndex:r===t?0:-1,"aria-selected":r===t,ref:e=>{l.push(e)},onKeyDown:c,onClick:u,...o,className:(0,n.A)("tabs__item",w.tabItem,o?.className,{"tabs__item--active":r===t}),children:a??t},t)}))})}function _(e){let{lazy:t,children:a,selectedValue:o}=e;const s=(Array.isArray(a)?a:[a]).filter(Boolean);if(t){const e=s.find((e=>e.props.value===o));return e?(0,r.cloneElement)(e,{className:(0,n.A)("margin-top--md",e.props.className)}):null}return(0,g.jsx)("div",{className:"margin-top--md",children:s.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==o})))})}function y(e){const t=b(e);return(0,g.jsxs)("div",{className:(0,n.A)("tabs-container",w.tabList),children:[(0,g.jsx)(f,{...t,...e}),(0,g.jsx)(_,{...t,...e})]})}function v(e){const t=(0,x.A)();return(0,g.jsx)(y,{...e,children:c(e.children)},String(t))}const j={tabItem:"tabItem_Ymn6"};function k(e){let{children:t,hidden:a,className:r}=e;return(0,g.jsx)("div",{role:"tabpanel",className:(0,n.A)(j.tabItem,r),hidden:a,children:t})}var A=a(17081);const T=function(e){let{languages:t}=e;const[n,o]=(0,r.useState)([]),s=(0,A.u)().frontMatter.id;return(0,r.useEffect)((()=>{(async()=>{const e=await Promise.all(t.map((async e=>{const t=(0,r.lazy)((()=>a(36217)(`./${s}/_${e.value}.mdx`)));return{label:e.label,component:t}})));o(e)})()}),[t]),(0,g.jsx)("div",{children:n.length>0&&(0,g.jsx)(v,{groupId:"elemental-selenium-tabs",children:n.map(((e,t)=>(0,g.jsx)(k,{value:e.label,label:e.label,children:(0,g.jsx)(r.Suspense,{fallback:(0,g.jsx)("div",{children:"Loading..."}),children:(0,g.jsx)(e.component,{})})},t)))})})}},59278:(e,t,a)=>{"use strict";a.d(t,{A:()=>r});const r=a.p+"assets/images/dave-haeffner-51c0929f88475823fb30e6519d3be0a3.jpeg"},36217:(e,t,a)=>{var r={"./1-upload-a-file/_csharp.mdx":[38724,1869,8069,8724],"./1-upload-a-file/_java.mdx":[57485,1869,8069,7485],"./1-upload-a-file/_javascript.mdx":[30828,1869,8069,828],"./1-upload-a-file/_python.mdx":[88359,1869,8069,8359],"./1-upload-a-file/_ruby.mdx":[13125,1869,8069,3125],"./1-upload-a-file/_selenide.mdx":[44622,1869,8069,4622],"./10-retry-test-actions/_ruby.mdx":[22066,2066],"./11-build-an-interactive-prompt/_ruby.mdx":[78816,8816],"./12-opt-out-of-ab-tests/_csharp.mdx":[20826,826],"./12-opt-out-of-ab-tests/_java.mdx":[25183,5183],"./12-opt-out-of-ab-tests/_javascript.mdx":[35562,5562],"./12-opt-out-of-ab-tests/_python.mdx":[63313,3313],"./12-opt-out-of-ab-tests/_ruby.mdx":[51447,1447],"./13-how-to-access-basic-auth/_csharp.mdx":[95226,5226],"./13-how-to-access-basic-auth/_java.mdx":[43135,3135],"./13-how-to-access-basic-auth/_javascript.mdx":[11242,1242],"./13-how-to-access-basic-auth/_python.mdx":[54481,4481],"./13-how-to-access-basic-auth/_ruby.mdx":[48247,8247],"./14-interactive-prompts-revisited/_ruby.mdx":[85241,5241],"./15-download-secure-files/_ruby.mdx":[4926,4926],"./16-take-screenshot-on-failure/_csharp.mdx":[65137,5137],"./16-take-screenshot-on-failure/_java.mdx":[62548,2548],"./16-take-screenshot-on-failure/_javascript.mdx":[12713,2713],"./16-take-screenshot-on-failure/_python.mdx":[97142,4761],"./16-take-screenshot-on-failure/_ruby.mdx":[14380,4380],"./17-retrieve-http-status-codes/_ruby.mdx":[47323,7323],"./19-data-driven-testing/_ruby.mdx":[58786,8786],"./2-download-a-file/_csharp.mdx":[54302,1869,8069,4302],"./2-download-a-file/_java.mdx":[78299,1869,8069,8299],"./2-download-a-file/_javascript.mdx":[50846,1869,8069,846],"./2-download-a-file/_python.mdx":[14989,1869,8069,4989],"./2-download-a-file/_ruby.mdx":[12163,1869,8069,2163],"./2-download-a-file/_selenide.mdx":[53460,1869,8069,3460],"./22-locator-strategy/_ruby.mdx":[40906,906],"./23-dynamic-pages/_ruby.mdx":[36057,6057],"./24-rest-apis/_ruby.mdx":[97298,7298],"./25-how-to-work-with-tables/_csharp.mdx":[56769,6769],"./25-how-to-work-with-tables/_java.mdx":[35716,5716],"./25-how-to-work-with-tables/_javascript.mdx":[94873,4873],"./25-how-to-work-with-tables/_python.mdx":[52678,2678],"./25-how-to-work-with-tables/_ruby.mdx":[41916,1916],"./26-cloud/_ruby.mdx":[67935,7935],"./27-parallel/_ruby.mdx":[75440,5440],"./29-chrome-driver/_csharp.mdx":[46743,6743],"./29-chrome-driver/_java.mdx":[78318,8318],"./29-chrome-driver/_python.mdx":[94808,4808],"./29-chrome-driver/_ruby.mdx":[48206,8206],"./3-work-with-frames/_csharp.mdx":[76141,1869,8069,6141],"./3-work-with-frames/_java.mdx":[79768,1869,8069,9768],"./3-work-with-frames/_javascript.mdx":[89349,1869,8069,9349],"./3-work-with-frames/_python.mdx":[67370,1869,8069,7370],"./3-work-with-frames/_ruby.mdx":[21632,1869,8069,1632],"./3-work-with-frames/_selenide.mdx":[1471,1869,8069,1471],"./3-work-with-frames/_serenity-js.mdx":[31573,1869,8069,1573],"./30-mobile/_ruby.mdx":[3247,3247],"./32-css-vs-xpath/_ruby.mdx":[38922,6541],"./33-css-vs-xpath-2/_ruby.mdx":[86892,6892],"./34-css-vs-xpath-3/_ruby.mdx":[58100,5719],"./38-headless/_ruby.mdx":[904,904],"./39-drag-and-drop/_ruby.mdx":[78644,8644],"./4-work-with-multiple-windows/_csharp.mdx":[92486,1869,8069,2486],"./4-work-with-multiple-windows/_java.mdx":[13219,1869,8069,3219],"./4-work-with-multiple-windows/_javascript.mdx":[69270,1869,8069,9270],"./4-work-with-multiple-windows/_python.mdx":[63941,1869,8069,3941],"./4-work-with-multiple-windows/_ruby.mdx":[5195,1869,8069,5195],"./4-work-with-multiple-windows/_selenide.mdx":[61148,1869,8069,1148],"./40-disabled-element/_csharp.mdx":[7540,7540],"./40-disabled-element/_java.mdx":[74941,4941],"./40-disabled-element/_javascript.mdx":[64188,4188],"./40-disabled-element/_python.mdx":[2327,2327],"./40-disabled-element/_ruby.mdx":[373,373],"./41-one-test-multiple-browsers/_ruby.mdx":[51257,1257],"./42-one-test-multiple-browsers-parallel/_ruby.mdx":[39942,9942],"./43-forgot-password/_ruby.mdx":[62686,2686],"./44-exception-handling/_ruby.mdx":[55505,5505],"./45-how-to-test-checkboxes/_csharp.mdx":[72477,2477],"./45-how-to-test-checkboxes/_java.mdx":[94184,4184],"./45-how-to-test-checkboxes/_javascript.mdx":[2229,2229],"./45-how-to-test-checkboxes/_python.mdx":[61178,1178],"./45-how-to-test-checkboxes/_ruby.mdx":[37584,7584],"./47-waiting/_ruby.mdx":[56118,6118],"./48-load-testing/_ruby.mdx":[93173,3173],"./49-performance-testing/_ruby.mdx":[6900,6900],"./5-select-from-a-dropdown/_csharp.mdx":[20699,1869,8069,699],"./5-select-from-a-dropdown/_java.mdx":[47850,1869,8069,7850],"./5-select-from-a-dropdown/_javascript.mdx":[55203,1869,8069,5203],"./5-select-from-a-dropdown/_python.mdx":[23156,1869,8069,3156],"./5-select-from-a-dropdown/_ruby.mdx":[18922,1869,8069,8922],"./5-select-from-a-dropdown/_selenide.mdx":[18977,1869,8069,8977],"./50-how-to-work-with-hovers/_csharp.mdx":[97523,7523],"./50-how-to-work-with-hovers/_java.mdx":[45954,5954],"./50-how-to-work-with-hovers/_javascript.mdx":[6027,6027],"./50-how-to-work-with-hovers/_python.mdx":[4028,4028],"./50-how-to-work-with-hovers/_ruby.mdx":[77346,7346],"./51-javascript-alerts/_csharp.mdx":[87716,7716],"./51-javascript-alerts/_java.mdx":[77805,7805],"./51-javascript-alerts/_javascript.mdx":[38284,8284],"./51-javascript-alerts/_python.mdx":[55495,5495],"./51-javascript-alerts/_ruby.mdx":[84485,4485],"./52-grid/_java.mdx":[70961,961],"./52-grid/_javascript.mdx":[65352,5352],"./52-grid/_python.mdx":[85899,5899],"./52-grid/_ruby.mdx":[81641,1641],"./53-growl/_csharp.mdx":[29718,9718],"./53-growl/_java.mdx":[24032,1651],"./53-growl/_javascript.mdx":[47142,7142],"./53-growl/_python.mdx":[17397,7397],"./53-growl/_ruby.mdx":[29435,9435],"./54-logging/_ruby.mdx":[74684,4684],"./55-wrapper/_ruby.mdx":[88263,8263],"./56-retry-failed-tests/_ruby.mdx":[52161,2161],"./57-junit-xml/_ruby.mdx":[50984,984],"./58-tagging/_ruby.mdx":[90742,742],"./6-open-new-window/_csharp.mdx":[56333,1869,8069,6333],"./6-open-new-window/_java.mdx":[96792,1869,8069,6792],"./6-open-new-window/_javascript.mdx":[80133,1869,8069,133],"./6-open-new-window/_python.mdx":[69098,1869,8069,9098],"./6-open-new-window/_ruby.mdx":[82560,1869,8069,2560],"./6-open-new-window/_selenide.mdx":[11839,1869,8069,1839],"./60-list-tags/_ruby.mdx":[56996,6996],"./61-how-to-press-keyboard-keys/_csharp.mdx":[9311,9311],"./61-how-to-press-keyboard-keys/_java.mdx":[74358,4358],"./61-how-to-press-keyboard-keys/_javascript.mdx":[24743,4743],"./61-how-to-press-keyboard-keys/_python.mdx":[43472,3472],"./61-how-to-press-keyboard-keys/_ruby.mdx":[85526,5526],"./63-right-click/_csharp.mdx":[56173,6173],"./63-right-click/_java.mdx":[6264,6264],"./63-right-click/_javascript.mdx":[12805,2805],"./63-right-click/_python.mdx":[73930,3930],"./63-right-click/_ruby.mdx":[58144,8144],"./64-limit-bandwidth/_ruby.mdx":[54451,4451],"./65-highlight-elements/_csharp.mdx":[37392,7392],"./65-highlight-elements/_java.mdx":[14929,4929],"./65-highlight-elements/_javascript.mdx":[57448,7448],"./65-highlight-elements/_python.mdx":[56395,6395],"./65-highlight-elements/_ruby.mdx":[37289,7289],"./66-blacklist/_ruby.mdx":[1281,1281],"./67-broken-images/_ruby.mdx":[84175,4175],"./68-load-testing-revisited/_ruby.mdx":[51327,1327],"./69-safari/_java.mdx":[85955,5955],"./69-safari/_ruby.mdx":[75627,5627],"./7-use-a-page-object/_ruby.mdx":[59200,9200],"./72-headless-chrome/_ruby.mdx":[18143,8143],"./8-download-a-file-revisited/_csharp.mdx":[80352,352],"./8-download-a-file-revisited/_java.mdx":[63681,3681],"./8-download-a-file-revisited/_python.mdx":[21435,1435],"./8-download-a-file-revisited/_ruby.mdx":[44121,4121],"./9-use-a-base-page-object/_ruby.mdx":[86506,6506]};function n(e){if(!a.o(r,e))return Promise.resolve().then((()=>{var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}));var t=r[e],n=t[0];return Promise.all(t.slice(1).map(a.e)).then((()=>a(n)))}n.keys=()=>Object.keys(r),n.id=36217,e.exports=n},28453:(e,t,a)=>{"use strict";a.d(t,{R:()=>s,x:()=>i});var r=a(96540);const n={},o=r.createContext(n);function s(e){const t=r.useContext(o);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function i(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:s(e.components),r.createElement(o.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.