How to use createStacklessError method in Playwright Internal

Best JavaScript code snippet using playwright-internal

injectedScriptSource.js

Source:injectedScriptSource.js Github

copy

Full Screen

...2772 parseSelector(e) {2773 const t = (0, s.parseSelector)(e)2774 for (const n of t.parts)2775 if (!this._engines.has(n.name))2776 throw this.createStacklessError(2777 `Unknown engine "${n.name}" while parsing selector ${e}`2778 )2779 return t2780 }2781 querySelector(e, t, n) {2782 if (!t.querySelector)2783 throw this.createStacklessError('Node is not queryable.')2784 this._evaluator.begin()2785 try {2786 var r, o2787 const i = this._querySelectorRecursively(2788 [{ element: t, capture: void 0 }],2789 e,2790 0,2791 new Map()2792 )2793 if (n && i.length > 1)2794 throw this.strictModeViolationError(2795 e,2796 i.map((e) => e.element)2797 )2798 return (2799 (null === (r = i[0]) || void 0 === r ? void 0 : r.capture) ||2800 (null === (o = i[0]) || void 0 === o ? void 0 : o.element)2801 )2802 } finally {2803 this._evaluator.end()2804 }2805 }2806 _querySelectorRecursively(e, t, n, r) {2807 if (n === t.parts.length) return e2808 const o = t.parts[n]2809 if ('nth' === o.name) {2810 let i = []2811 if ('0' === o.body) i = e.slice(0, 1)2812 else if ('-1' === o.body) e.length && (i = e.slice(e.length - 1))2813 else {2814 if ('number' == typeof t.capture)2815 throw this.createStacklessError(2816 "Can't query n-th element in a request with the capture."2817 )2818 const n = +o.body,2819 r = new Set()2820 for (const t of e) r.add(t.element), n + 1 === r.size && (i = [t])2821 }2822 return this._querySelectorRecursively(i, t, n + 1, r)2823 }2824 if ('visible' === o.name) {2825 const i = Boolean(o.body),2826 s = e.filter((e) => i === (0, c.isVisible)(e.element))2827 return this._querySelectorRecursively(s, t, n + 1, r)2828 }2829 const i = []2830 for (const o of e) {2831 const e = n - 1 === t.capture ? o.element : o.capture2832 let s = r.get(o.element)2833 s || ((s = []), r.set(o.element, s))2834 let c = s[n]2835 c || ((c = this._queryEngineAll(t.parts[n], o.element)), (s[n] = c))2836 for (const t of c) {2837 if (!('nodeName' in t))2838 throw this.createStacklessError(2839 `Expected a Node but got ${Object.prototype.toString.call(t)}`2840 )2841 i.push({ element: t, capture: e })2842 }2843 }2844 return this._querySelectorRecursively(i, t, n + 1, r)2845 }2846 querySelectorAll(e, t) {2847 if (!t.querySelectorAll)2848 throw this.createStacklessError('Node is not queryable.')2849 this._evaluator.begin()2850 try {2851 const n = this._querySelectorRecursively(2852 [{ element: t, capture: void 0 }],2853 e,2854 0,2855 new Map()2856 ),2857 r = new Set()2858 for (const e of n) r.add(e.capture || e.element)2859 return [...r]2860 } finally {2861 this._evaluator.end()2862 }2863 }2864 _queryEngineAll(e, t) {2865 return this._engines.get(e.name).queryAll(t, e.body)2866 }2867 _createAttributeEngine(e, t) {2868 return {2869 queryAll: (n, r) =>2870 this._evaluator.query(2871 { scope: n, pierceShadow: t },2872 ((t) => [2873 {2874 simples: [2875 {2876 selector: {2877 css: `[${e}=${JSON.stringify(t)}]`,2878 functions: []2879 },2880 combinator: ''2881 }2882 ]2883 }2884 ])(r)2885 )2886 }2887 }2888 _createCSSEngine() {2889 const e = this._evaluator2890 return {2891 queryAll: (t, n) => e.query({ scope: t, pierceShadow: !0 }, n)2892 }2893 }2894 _createTextEngine(e) {2895 const t = (t, n) => {2896 const { matcher: r, kind: o } = (function (e) {2897 if ('/' === e[0] && e.lastIndexOf('/') > 0) {2898 const t = e.lastIndexOf('/')2899 return {2900 matcher: (0, c.createRegexTextMatcher)(2901 e.substring(1, t),2902 e.substring(t + 1)2903 ),2904 kind: 'regex'2905 }2906 }2907 let t = !12908 return (2909 e.length > 1 &&2910 '"' === e[0] &&2911 '"' === e[e.length - 1] &&2912 ((e = f(e.substring(1, e.length - 1))), (t = !0)),2913 e.length > 1 &&2914 "'" === e[0] &&2915 "'" === e[e.length - 1] &&2916 ((e = f(e.substring(1, e.length - 1))), (t = !0)),2917 {2918 matcher: t2919 ? (0, c.createStrictTextMatcher)(e)2920 : (0, c.createLaxTextMatcher)(e),2921 kind: t ? 'strict' : 'lax'2922 }2923 )2924 })(n),2925 i = []2926 let s = null2927 const a = (e) => {2928 if ('lax' === o && s && s.contains(e)) return !12929 const t = (0, c.elementMatchesText)(this._evaluator, e, r)2930 'none' === t && (s = e),2931 ('self' === t || ('selfAndChildren' === t && 'strict' === o)) &&2932 i.push(e)2933 }2934 t.nodeType === Node.ELEMENT_NODE && a(t)2935 const u = this._evaluator._queryCSS(2936 { scope: t, pierceShadow: e },2937 '*'2938 )2939 for (const e of u) a(e)2940 return i2941 }2942 return { queryAll: (e, n) => t(e, n) }2943 }2944 extend(e, t) {2945 return new (n.g.eval(2946 `\n (() => {\n ${e}\n return pwExport;\n })()`2947 ))(this, t)2948 }2949 isVisible(e) {2950 return (0, c.isVisible)(e)2951 }2952 pollRaf(e) {2953 return this.poll(e, (e) => requestAnimationFrame(e))2954 }2955 pollInterval(e, t) {2956 return this.poll(t, (t) => setTimeout(t, e))2957 }2958 pollLogScale(e) {2959 const t = [100, 250, 500]2960 let n = 02961 return this.poll(e, (e) => setTimeout(e, t[n++] || 1e3))2962 }2963 poll(e, t) {2964 return this._runAbortableTask((n) => {2965 let r, o2966 const i = new Promise((e, t) => {2967 ;(r = e), (o = t)2968 }),2969 s = () => {2970 if (!n.aborted)2971 try {2972 const o = e(n)2973 o !== n.continuePolling ? r(o) : t(s)2974 } catch (e) {2975 n.log(' ' + e.message), o(e)2976 }2977 }2978 return s(), i2979 })2980 }2981 _runAbortableTask(e) {2982 let t,2983 n = [],2984 r = !12985 const o = () => {2986 t && (t(n), (n = []), (t = void 0))2987 }2988 let i,2989 s = ''2990 const c = {2991 injectedScript: this,2992 aborted: !1,2993 continuePolling: Symbol('continuePolling'),2994 log: (e) => {2995 ;(s = e), n.push({ message: e }), o()2996 },2997 logRepeating: (e) => {2998 e !== s && c.log(e)2999 },3000 setIntermediateResult: (e) => {3001 i !== e && ((i = e), n.push({ intermediateResult: e }), o())3002 }3003 }3004 return {3005 takeNextLogs: () =>3006 new Promise((e) => {3007 ;(t = e), (n.length || r) && o()3008 }),3009 run: () => {3010 const t = e(c)3011 return (3012 t.finally(() => {3013 ;(r = !0), o()3014 }),3015 t3016 )3017 },3018 cancel: () => {3019 c.aborted = !03020 },3021 takeLastLogs: () => n3022 }3023 }3024 getElementBorderWidth(e) {3025 if (3026 e.nodeType !== Node.ELEMENT_NODE ||3027 !e.ownerDocument ||3028 !e.ownerDocument.defaultView3029 )3030 return { left: 0, top: 0 }3031 const t = e.ownerDocument.defaultView.getComputedStyle(e)3032 return {3033 left: parseInt(t.borderLeftWidth || '', 10),3034 top: parseInt(t.borderTopWidth || '', 10)3035 }3036 }3037 retarget(e, t) {3038 let n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement3039 return n3040 ? (n.matches('input, textarea, select') ||3041 (n =3042 n.closest(3043 'button, [role=button], [role=checkbox], [role=radio]'3044 ) || n),3045 'follow-label' === t &&3046 (n.matches(3047 'input, textarea, button, select, [role=button], [role=checkbox], [role=radio]'3048 ) ||3049 n.isContentEditable ||3050 (n = n.closest('label') || n),3051 'LABEL' === n.nodeName && (n = n.control || n)),3052 n)3053 : null3054 }3055 waitForElementStatesAndPerformAction(e, t, n, r) {3056 let o,3057 i = 0,3058 s = 0,3059 c = 03060 return this.pollRaf((a) => {3061 if (n) return a.log(' forcing action'), r(e, a)3062 for (const n of t) {3063 if ('stable' !== n) {3064 const t = this.elementState(e, n)3065 if ('boolean' != typeof t) return t3066 if (!t)3067 return (3068 a.logRepeating(` element is not ${n} - waiting...`),3069 a.continuePolling3070 )3071 continue3072 }3073 const t = this.retarget(e, 'no-follow-label')3074 if (!t) return 'error:notconnected'3075 if (1 == ++i) return a.continuePolling3076 const r = performance.now()3077 if (this._stableRafCount > 1 && r - c < 15) return a.continuePolling3078 c = r3079 const u = t.getBoundingClientRect(),3080 l = { x: u.top, y: u.left, width: u.width, height: u.height }3081 o &&3082 l.x === o.x &&3083 l.y === o.y &&3084 l.width === o.width &&3085 l.height === o.height3086 ? ++s3087 : (s = 0)3088 const h = s >= this._stableRafCount,3089 p = h || !o3090 if (3091 ((o = l),3092 p || a.logRepeating(' element is not stable - waiting...'),3093 !h)3094 )3095 return a.continuePolling3096 }3097 return r(e, a)3098 })3099 }3100 elementState(e, t) {3101 const n = this.retarget(3102 e,3103 ['stable', 'visible', 'hidden'].includes(t)3104 ? 'no-follow-label'3105 : 'follow-label'3106 )3107 if (!n || !n.isConnected) return 'hidden' === t || 'error:notconnected'3108 if ('visible' === t) return this.isVisible(n)3109 if ('hidden' === t) return !this.isVisible(n)3110 const r =3111 ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes(n.nodeName) &&3112 n.hasAttribute('disabled')3113 if ('disabled' === t) return r3114 if ('enabled' === t) return !r3115 const o = !(3116 ['INPUT', 'TEXTAREA', 'SELECT'].includes(n.nodeName) &&3117 n.hasAttribute('readonly')3118 )3119 if ('editable' === t) return !r && o3120 if ('checked' === t) {3121 if (['checkbox', 'radio'].includes(n.getAttribute('role') || ''))3122 return 'true' === n.getAttribute('aria-checked')3123 if ('INPUT' !== n.nodeName)3124 throw this.createStacklessError('Not a checkbox or radio button')3125 if (!['radio', 'checkbox'].includes(n.type.toLowerCase()))3126 throw this.createStacklessError('Not a checkbox or radio button')3127 return n.checked3128 }3129 throw this.createStacklessError(`Unexpected element state "${t}"`)3130 }3131 selectOptions(e, t, n) {3132 const r = this.retarget(t, 'follow-label')3133 if (!r) return 'error:notconnected'3134 if ('select' !== r.nodeName.toLowerCase())3135 throw this.createStacklessError('Element is not a <select> element')3136 const o = r,3137 i = [...o.options],3138 s = []3139 let c = e.slice()3140 for (let e = 0; e < i.length; e++) {3141 const t = i[e],3142 n = (n) => {3143 if (n instanceof Node) return t === n3144 let r = !03145 return (3146 void 0 !== n.value && (r = r && n.value === t.value),3147 void 0 !== n.label && (r = r && n.label === t.label),3148 void 0 !== n.index && (r = r && n.index === e),3149 r3150 )3151 }3152 if (c.some(n)) {3153 if ((s.push(t), !o.multiple)) {3154 c = []3155 break3156 }3157 c = c.filter((e) => !n(e))3158 }3159 }3160 return c.length3161 ? (n.logRepeating(' did not find some options - waiting... '),3162 n.continuePolling)3163 : ((o.value = void 0),3164 s.forEach((e) => (e.selected = !0)),3165 n.log(' selected specified option(s)'),3166 o.dispatchEvent(new Event('input', { bubbles: !0 })),3167 o.dispatchEvent(new Event('change', { bubbles: !0 })),3168 s.map((e) => e.value))3169 }3170 fill(e, t, n) {3171 const r = this.retarget(t, 'follow-label')3172 if (!r) return 'error:notconnected'3173 if ('input' === r.nodeName.toLowerCase()) {3174 const t = r,3175 o = t.type.toLowerCase(),3176 i = new Set([3177 'date',3178 'time',3179 'datetime',3180 'datetime-local',3181 'month',3182 'week'3183 ])3184 if (3185 !new Set([3186 '',3187 'email',3188 'number',3189 'password',3190 'search',3191 'tel',3192 'text',3193 'url'3194 ]).has(o) &&3195 !i.has(o)3196 )3197 throw (3198 (n.log(` input of type "${o}" cannot be filled`),3199 this.createStacklessError(3200 `Input of type "${o}" cannot be filled`3201 ))3202 )3203 if ('number' === o && ((e = e.trim()), isNaN(Number(e))))3204 throw this.createStacklessError(3205 'Cannot type text into input[type=number]'3206 )3207 if (i.has(o)) {3208 if (((e = e.trim()), t.focus(), (t.value = e), t.value !== e))3209 throw this.createStacklessError('Malformed value')3210 return (3211 r.dispatchEvent(new Event('input', { bubbles: !0 })),3212 r.dispatchEvent(new Event('change', { bubbles: !0 })),3213 'done'3214 )3215 }3216 } else if ('textarea' === r.nodeName.toLowerCase());3217 else if (!r.isContentEditable)3218 throw this.createStacklessError(3219 'Element is not an <input>, <textarea> or [contenteditable] element'3220 )3221 return this.selectText(r), 'needsinput'3222 }3223 selectText(e) {3224 const t = this.retarget(e, 'follow-label')3225 if (!t) return 'error:notconnected'3226 if ('input' === t.nodeName.toLowerCase()) {3227 const e = t3228 return e.select(), e.focus(), 'done'3229 }3230 if ('textarea' === t.nodeName.toLowerCase()) {3231 const e = t3232 return (3233 (e.selectionStart = 0),3234 (e.selectionEnd = e.value.length),3235 e.focus(),3236 'done'3237 )3238 }3239 const n = t.ownerDocument.createRange()3240 n.selectNodeContents(t)3241 const r = t.ownerDocument.defaultView.getSelection()3242 return r && (r.removeAllRanges(), r.addRange(n)), t.focus(), 'done'3243 }3244 focusNode(e, t) {3245 if (!e.isConnected) return 'error:notconnected'3246 if (e.nodeType !== Node.ELEMENT_NODE)3247 throw this.createStacklessError('Node is not an element')3248 const n =3249 e.getRootNode().activeElement === e &&3250 e.ownerDocument &&3251 e.ownerDocument.hasFocus()3252 if ((e.focus(), t && !n && 'input' === e.nodeName.toLowerCase()))3253 try {3254 e.setSelectionRange(0, 0)3255 } catch (e) {}3256 return 'done'3257 }3258 setInputFiles(e, t) {3259 if (e.nodeType !== Node.ELEMENT_NODE)3260 return 'Node is not of type HTMLElement'3261 const n = e3262 if ('INPUT' !== n.nodeName) return 'Not an <input> element'3263 const r = n3264 if ('file' !== (r.getAttribute('type') || '').toLowerCase())3265 return 'Not an input[type=file] element'3266 const o = t.map((e) => {3267 const t = Uint8Array.from(atob(e.buffer), (e) => e.charCodeAt(0))3268 return new File([t], e.name, { type: e.mimeType })3269 }),3270 i = new DataTransfer()3271 for (const e of o) i.items.add(e)3272 ;(r.files = i.files),3273 r.dispatchEvent(new Event('input', { bubbles: !0 })),3274 r.dispatchEvent(new Event('change', { bubbles: !0 }))3275 }3276 checkHitTargetAt(e, t) {3277 let n = e.nodeType === Node.ELEMENT_NODE ? e : e.parentElement3278 if (!n || !n.isConnected) return 'error:notconnected'3279 n = n.closest('button, [role=button]') || n3280 let r = this.deepElementFromPoint(document, t.x, t.y)3281 const o = []3282 for (; r && r !== n; )3283 o.push(r), (r = (0, c.parentElementOrShadowHost)(r))3284 if (r === n) return 'done'3285 const i = this.previewNode(o[0])3286 let s3287 for (; n; ) {3288 const e = o.indexOf(n)3289 if (-1 !== e) {3290 e > 1 && (s = this.previewNode(o[e - 1]))3291 break3292 }3293 n = (0, c.parentElementOrShadowHost)(n)3294 }3295 return s3296 ? { hitTargetDescription: `${i} from ${s} subtree` }3297 : { hitTargetDescription: i }3298 }3299 dispatchEvent(e, t, n) {3300 let r3301 switch (3302 ((n = { bubbles: !0, cancelable: !0, composed: !0, ...n }), p.get(t))3303 ) {3304 case 'mouse':3305 r = new MouseEvent(t, n)3306 break3307 case 'keyboard':3308 r = new KeyboardEvent(t, n)3309 break3310 case 'touch':3311 r = new TouchEvent(t, n)3312 break3313 case 'pointer':3314 r = new PointerEvent(t, n)3315 break3316 case 'focus':3317 r = new FocusEvent(t, n)3318 break3319 case 'drag':3320 r = new DragEvent(t, n)3321 break3322 default:3323 r = new Event(t, n)3324 }3325 e.dispatchEvent(r)3326 }3327 deepElementFromPoint(e, t, n) {3328 let r,3329 o = e3330 for (; o; ) {3331 const e = o.elementsFromPoint(t, n)[0]3332 if (!e || r === e) break3333 ;(r = e), (o = r.shadowRoot)3334 }3335 return r3336 }3337 previewNode(e) {3338 if (e.nodeType === Node.TEXT_NODE)3339 return h(`#text=${e.nodeValue || ''}`)3340 if (e.nodeType !== Node.ELEMENT_NODE)3341 return h(`<${e.nodeName.toLowerCase()} />`)3342 const t = e,3343 n = []3344 for (let e = 0; e < t.attributes.length; e++) {3345 const { name: r, value: o } = t.attributes[e]3346 'style' === r ||3347 r.startsWith('__playwright') ||3348 (!o && l.has(r) ? n.push(` ${r}`) : n.push(` ${r}="${o}"`))3349 }3350 n.sort((e, t) => e.length - t.length)3351 let r = n.join('')3352 if (3353 (r.length > 50 && (r = r.substring(0, 49) + '…'), u.has(t.nodeName))3354 )3355 return h(`<${t.nodeName.toLowerCase()}${r}/>`)3356 const o = t.childNodes3357 let i = !13358 if (o.length <= 5) {3359 i = !03360 for (let e = 0; e < o.length; e++)3361 i = i && o[e].nodeType === Node.TEXT_NODE3362 }3363 let s = i ? t.textContent || '' : o.length ? '…' : ''3364 return (3365 s.length > 50 && (s = s.substring(0, 49) + '…'),3366 h(3367 `<${t.nodeName.toLowerCase()}${r}>${s}</${t.nodeName.toLowerCase()}>`3368 )3369 )3370 }3371 strictModeViolationError(e, t) {3372 const n = t3373 .slice(0, 10)3374 .map((e) => ({3375 preview: this.previewNode(e),3376 selector: (0, a.generateSelector)(this, e).selector3377 })),3378 r = n.map(3379 (e, t) =>3380 `\n ${t + 1}) ${e.preview} aka playwright.$("${e.selector}")`3381 )3382 return (3383 n.length < t.length && r.push('\n ...'),3384 this.createStacklessError(3385 `strict mode violation: "${e.selector}" resolved to ${3386 t.length3387 } elements:${r.join('')}\n`3388 )3389 )3390 }3391 createStacklessError(e) {3392 if ('firefox' === this._browserName) {3393 const t = new Error('Error: ' + e)3394 return (t.stack = ''), t3395 }3396 const t = new Error(e)3397 return delete t.stack, t3398 }3399 _setupGlobalListenersRemovalDetection() {3400 const e = '__playwright_global_listeners_check__'3401 let t = !13402 const n = () => (t = !0)3403 window.addEventListener(e, n),3404 new MutationObserver((r) => {3405 if (3406 r.some((e) =>3407 Array.from(e.addedNodes).includes(document.documentElement)3408 ) &&3409 ((t = !1), window.dispatchEvent(new CustomEvent(e)), !t)3410 ) {3411 window.addEventListener(e, n)3412 for (const e of this.onGlobalListenersRemoved) e()3413 }3414 }).observe(document, { childList: !0 })3415 }3416 expectSingleElement(e, t, n) {3417 const r = e.injectedScript,3418 o = n.expression3419 {3420 let n3421 if ('to.be.checked' === o)3422 n = e.injectedScript.elementState(t, 'checked')3423 else if ('to.be.disabled' === o)3424 n = e.injectedScript.elementState(t, 'disabled')3425 else if ('to.be.editable' === o)3426 n = e.injectedScript.elementState(t, 'editable')3427 else if ('to.be.empty' === o) {3428 var i3429 n =3430 'INPUT' === t.nodeName || 'TEXTAREA' === t.nodeName3431 ? !t.value3432 : !(null !== (i = t.textContent) && void 0 !== i && i.trim())3433 } else3434 'to.be.enabled' === o3435 ? (n = e.injectedScript.elementState(t, 'enabled'))3436 : 'to.be.focused' === o3437 ? (n = document.activeElement === t)3438 : 'to.be.hidden' === o3439 ? (n = e.injectedScript.elementState(t, 'hidden'))3440 : 'to.be.visible' === o &&3441 (n = e.injectedScript.elementState(t, 'visible'))3442 if (void 0 !== n) {3443 if ('error:notcheckbox' === n)3444 throw r.createStacklessError('Element is not a checkbox')3445 if ('error:notconnected' === n)3446 throw r.createStacklessError('Element is not connected')3447 return { received: n, matches: n }3448 }3449 }3450 if ('to.have.property' === o) {3451 const e = t[n.expressionArg]3452 return { received: e, matches: m(e, n.expectedValue) }3453 }3454 {3455 let e3456 if ('to.have.attribute' === o)3457 e = t.getAttribute(n.expressionArg) || ''3458 else if ('to.have.class' === o) e = t.className3459 else if ('to.have.css' === o)3460 e = window.getComputedStyle(t)[n.expressionArg]3461 else if ('to.have.id' === o) e = t.id3462 else if ('to.have.text' === o)3463 e = n.useInnerText ? t.innerText : t.textContent || ''3464 else if ('to.have.title' === o) e = document.title3465 else if ('to.have.url' === o) e = document.location.href3466 else if ('to.have.value' === o) {3467 if (3468 'INPUT' !== t.nodeName &&3469 'TEXTAREA' !== t.nodeName &&3470 'SELECT' !== t.nodeName3471 )3472 throw this.createStacklessError('Not an input element')3473 e = t.value3474 }3475 if (void 0 !== e && n.expectedText)3476 return { received: e, matches: new d(n.expectedText[0]).matches(e) }3477 }3478 throw this.createStacklessError('Unknown expect matcher: ' + o)3479 }3480 expectArray(e, t) {3481 const n = t.expression3482 if ('to.have.count' === n) {3483 const n = e.length3484 return { received: n, matches: n === t.expectedNumber }3485 }3486 let r3487 if (3488 ('to.have.text.array' === n || 'to.contain.text.array' === n3489 ? (r = e.map((e) =>3490 t.useInnerText ? e.innerText : e.textContent || ''3491 ))3492 : 'to.have.class.array' === n && (r = e.map((e) => e.className)),3493 r && t.expectedText)3494 ) {3495 const e = 'to.contain.text.array' !== n3496 if (r.length !== t.expectedText.length && e)3497 return { received: r, matches: !1 }3498 let o = 03499 const i = t.expectedText.map((e) => new d(e))3500 let s = !03501 for (const e of i) {3502 for (; o < r.length && !e.matches(r[o]); ) o++3503 if (o >= r.length) {3504 s = !13505 break3506 }3507 }3508 return { received: r, matches: s }3509 }3510 throw this.createStacklessError('Unknown expect matcher: ' + n)3511 }3512 }3513 e.default = g3514 })(),3515 (pwExport = r.default)...

Full Screen

Full Screen

frames.js

Source:frames.js Github

copy

Full Screen

...852 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => element.textContent, undefined, options);853 }854 async innerText(metadata, selector, options = {}) {855 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => {856 if (element.namespaceURI !== 'http://www.w3.org/1999/xhtml') throw progress.injectedScript.createStacklessError('Node is not an HTMLElement');857 return element.innerText;858 }, undefined, options);859 }860 async innerHTML(metadata, selector, options = {}) {861 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => element.innerHTML, undefined, options);862 }863 async getAttribute(metadata, selector, name, options = {}) {864 return this._scheduleRerunnableTask(metadata, selector, (progress, element, data) => element.getAttribute(data.name), {865 name866 }, options);867 }868 async inputValue(metadata, selector, options = {}) {869 return this._scheduleRerunnableTask(metadata, selector, (progress, element) => {870 if (element.nodeName !== 'INPUT' && element.nodeName !== 'TEXTAREA' && element.nodeName !== 'SELECT') throw progress.injectedScript.createStacklessError('Node is not an <input>, <textarea> or <select> element');871 return element.value;872 }, undefined, options);873 }874 async _elementState(metadata, selector, state, options = {}) {875 const result = await this._scheduleRerunnableTask(metadata, selector, (progress, element, data) => {876 const injected = progress.injectedScript;877 return injected.elementState(element, data.state);878 }, {879 state880 }, options);881 return dom.throwRetargetableDOMError(result);882 }883 async isVisible(metadata, selector, options = {}) {884 const controller = new _progress.ProgressController(metadata, this);...

Full Screen

Full Screen

dom.js

Source:dom.js Github

copy

Full Screen

...165 return this._page._delegate.getContentFrame(this);166 }167 async getAttribute(name) {168 return throwRetargetableDOMError(await this.evaluateInUtility(([injected, node, name]) => {169 if (node.nodeType !== Node.ELEMENT_NODE) throw injected.createStacklessError('Node is not an element');170 const element = node;171 return {172 value: element.getAttribute(name)173 };174 }, name)).value;175 }176 async inputValue() {177 return throwRetargetableDOMError(await this.evaluateInUtility(([injected, node]) => {178 if (node.nodeType !== Node.ELEMENT_NODE || node.nodeName !== 'INPUT' && node.nodeName !== 'TEXTAREA' && node.nodeName !== 'SELECT') throw injected.createStacklessError('Node is not an <input>, <textarea> or <select> element');179 const element = node;180 return {181 value: element.value182 };183 }, undefined)).value;184 }185 async textContent() {186 return throwRetargetableDOMError(await this.evaluateInUtility(([injected, node]) => {187 return {188 value: node.textContent189 };190 }, undefined)).value;191 }192 async innerText() {193 return throwRetargetableDOMError(await this.evaluateInUtility(([injected, node]) => {194 if (node.nodeType !== Node.ELEMENT_NODE) throw injected.createStacklessError('Node is not an element');195 if (node.namespaceURI !== 'http://www.w3.org/1999/xhtml') throw injected.createStacklessError('Node is not an HTMLElement');196 const element = node;197 return {198 value: element.innerText199 };200 }, undefined)).value;201 }202 async innerHTML() {203 return throwRetargetableDOMError(await this.evaluateInUtility(([injected, node]) => {204 if (node.nodeType !== Node.ELEMENT_NODE) throw injected.createStacklessError('Node is not an element');205 const element = node;206 return {207 value: element.innerHTML208 };209 }, undefined)).value;210 }211 async dispatchEvent(type, eventInit = {}) {212 await this._evaluateInMainAndWaitForSignals(([injected, node, {213 type,214 eventInit215 }]) => injected.dispatchEvent(node, type, eventInit), {216 type,217 eventInit218 });219 await this._page._doSlowMo();220 }221 async _scrollRectIntoViewIfNeeded(rect) {222 return await this._page._delegate.scrollRectIntoViewIfNeeded(this, rect);223 }224 async _waitAndScrollIntoViewIfNeeded(progress) {225 while (progress.isRunning()) {226 assertDone(throwRetargetableDOMError(await this._waitForDisplayedAtStablePosition(progress, false227 /* force */228 , false229 /* waitForEnabled */230 )));231 progress.throwIfAborted(); // Avoid action that has side-effects.232 const result = throwRetargetableDOMError(await this._scrollRectIntoViewIfNeeded());233 if (result === 'error:notvisible') continue;234 assertDone(result);235 return;236 }237 }238 async scrollIntoViewIfNeeded(metadata, options = {}) {239 const controller = new _progress.ProgressController(metadata, this);240 return controller.run(progress => this._waitAndScrollIntoViewIfNeeded(progress), this._page._timeoutSettings.timeout(options));241 }242 async _clickablePoint() {243 const intersectQuadWithViewport = quad => {244 return quad.map(point => ({245 x: Math.min(Math.max(point.x, 0), metrics.width),246 y: Math.min(Math.max(point.y, 0), metrics.height)247 }));248 };249 const computeQuadArea = quad => {250 // Compute sum of all directed areas of adjacent triangles251 // https://en.wikipedia.org/wiki/Polygon#Simple_polygons252 let area = 0;253 for (let i = 0; i < quad.length; ++i) {254 const p1 = quad[i];255 const p2 = quad[(i + 1) % quad.length];256 area += (p1.x * p2.y - p2.x * p1.y) / 2;257 }258 return Math.abs(area);259 };260 const [quads, metrics] = await Promise.all([this._page._delegate.getContentQuads(this), this._page.mainFrame()._utilityContext().then(utility => utility.evaluate(() => ({261 width: innerWidth,262 height: innerHeight263 })))]);264 if (!quads || !quads.length) return 'error:notvisible'; // Allow 1x1 elements. Compensate for rounding errors by comparing with 0.99 instead.265 const filtered = quads.map(quad => intersectQuadWithViewport(quad)).filter(quad => computeQuadArea(quad) > 0.99);266 if (!filtered.length) return 'error:notinviewport'; // Return the middle point of the first quad.267 const result = {268 x: 0,269 y: 0270 };271 for (const point of filtered[0]) {272 result.x += point.x / 4;273 result.y += point.y / 4;274 }275 compensateHalfIntegerRoundingError(result);276 return result;277 }278 async _offsetPoint(offset) {279 const [box, border] = await Promise.all([this.boundingBox(), this.evaluateInUtility(([injected, node]) => injected.getElementBorderWidth(node), {}).catch(e => {})]);280 if (!box || !border) return 'error:notvisible';281 if (border === 'error:notconnected') return border; // Make point relative to the padding box to align with offsetX/offsetY.282 return {283 x: box.x + border.left + offset.x,284 y: box.y + border.top + offset.y285 };286 }287 async _retryPointerAction(progress, actionName, waitForEnabled, action, options) {288 let retry = 0; // We progressively wait longer between retries, up to 500ms.289 const waitTime = [0, 20, 100, 100, 500]; // By default, we scroll with protocol method to reveal the action point.290 // However, that might not work to scroll from under position:sticky elements291 // that overlay the target element. To fight this, we cycle through different292 // scroll alignments. This works in most scenarios.293 const scrollOptions = [undefined, {294 block: 'end',295 inline: 'end'296 }, {297 block: 'center',298 inline: 'center'299 }, {300 block: 'start',301 inline: 'start'302 }];303 while (progress.isRunning()) {304 if (retry) {305 progress.log(`retrying ${actionName} action${options.trial ? ' (trial run)' : ''}, attempt #${retry}`);306 const timeout = waitTime[Math.min(retry - 1, waitTime.length - 1)];307 if (timeout) {308 progress.log(` waiting ${timeout}ms`);309 const result = await this.evaluateInUtility(([injected, node, timeout]) => new Promise(f => setTimeout(f, timeout)), timeout);310 if (result === 'error:notconnected') return result;311 }312 } else {313 progress.log(`attempting ${actionName} action${options.trial ? ' (trial run)' : ''}`);314 }315 const forceScrollOptions = scrollOptions[retry % scrollOptions.length];316 const result = await this._performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options);317 ++retry;318 if (result === 'error:notvisible') {319 if (options.force) throw new Error('Element is not visible');320 progress.log(' element is not visible');321 continue;322 }323 if (result === 'error:notinviewport') {324 if (options.force) throw new Error('Element is outside of the viewport');325 progress.log(' element is outside of the viewport');326 continue;327 }328 if (typeof result === 'object' && 'hitTargetDescription' in result) {329 if (options.force) throw new Error(`Element does not receive pointer events, ${result.hitTargetDescription} intercepts them`);330 progress.log(` ${result.hitTargetDescription} intercepts pointer events`);331 continue;332 }333 return result;334 }335 return 'done';336 }337 async _performPointerAction(progress, actionName, waitForEnabled, action, forceScrollOptions, options) {338 const {339 force = false,340 position341 } = options;342 if (options.__testHookBeforeStable) await options.__testHookBeforeStable();343 const result = await this._waitForDisplayedAtStablePosition(progress, force, waitForEnabled);344 if (result !== 'done') return result;345 if (options.__testHookAfterStable) await options.__testHookAfterStable();346 progress.log(' scrolling into view if needed');347 progress.throwIfAborted(); // Avoid action that has side-effects.348 if (forceScrollOptions) {349 const scrolled = await this.evaluateInUtility(([injected, node, options]) => {350 if (node.nodeType === 1351 /* Node.ELEMENT_NODE */352 ) node.scrollIntoView(options);353 }, forceScrollOptions);354 if (scrolled === 'error:notconnected') return scrolled;355 } else {356 const scrolled = await this._scrollRectIntoViewIfNeeded(position ? {357 x: position.x,358 y: position.y,359 width: 0,360 height: 0361 } : undefined);362 if (scrolled !== 'done') return scrolled;363 }364 progress.log(' done scrolling');365 const maybePoint = position ? await this._offsetPoint(position) : await this._clickablePoint();366 if (typeof maybePoint === 'string') return maybePoint;367 const point = roundPoint(maybePoint);368 if (!force) {369 if (options.__testHookBeforeHitTarget) await options.__testHookBeforeHitTarget();370 progress.log(` checking that element receives pointer events at (${point.x},${point.y})`);371 const hitTargetResult = await this._checkHitTargetAt(point);372 if (hitTargetResult !== 'done') return hitTargetResult;373 progress.log(` element does receive pointer events`);374 }375 progress.metadata.point = point;376 if (options.trial) {377 progress.log(` trial ${actionName} has finished`);378 return 'done';379 }380 await progress.beforeInputAction(this);381 await this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {382 if (options.__testHookBeforePointerAction) await options.__testHookBeforePointerAction();383 progress.throwIfAborted(); // Avoid action that has side-effects.384 let restoreModifiers;385 if (options && options.modifiers) restoreModifiers = await this._page.keyboard._ensureModifiers(options.modifiers);386 progress.log(` performing ${actionName} action`);387 await action(point);388 progress.log(` ${actionName} action done`);389 progress.log(' waiting for scheduled navigations to finish');390 if (options.__testHookAfterPointerAction) await options.__testHookAfterPointerAction();391 if (restoreModifiers) await this._page.keyboard._ensureModifiers(restoreModifiers);392 }, 'input');393 progress.log(' navigations have finished');394 return 'done';395 }396 async hover(metadata, options) {397 const controller = new _progress.ProgressController(metadata, this);398 return controller.run(async progress => {399 const result = await this._hover(progress, options);400 return assertDone(throwRetargetableDOMError(result));401 }, this._page._timeoutSettings.timeout(options));402 }403 _hover(progress, options) {404 return this._retryPointerAction(progress, 'hover', false405 /* waitForEnabled */406 , point => this._page.mouse.move(point.x, point.y), options);407 }408 async click(metadata, options = {}) {409 const controller = new _progress.ProgressController(metadata, this);410 return controller.run(async progress => {411 const result = await this._click(progress, options);412 return assertDone(throwRetargetableDOMError(result));413 }, this._page._timeoutSettings.timeout(options));414 }415 _click(progress, options) {416 return this._retryPointerAction(progress, 'click', true417 /* waitForEnabled */418 , point => this._page.mouse.click(point.x, point.y, options), options);419 }420 async dblclick(metadata, options) {421 const controller = new _progress.ProgressController(metadata, this);422 return controller.run(async progress => {423 const result = await this._dblclick(progress, options);424 return assertDone(throwRetargetableDOMError(result));425 }, this._page._timeoutSettings.timeout(options));426 }427 _dblclick(progress, options) {428 return this._retryPointerAction(progress, 'dblclick', true429 /* waitForEnabled */430 , point => this._page.mouse.dblclick(point.x, point.y, options), options);431 }432 async tap(metadata, options = {}) {433 const controller = new _progress.ProgressController(metadata, this);434 return controller.run(async progress => {435 const result = await this._tap(progress, options);436 return assertDone(throwRetargetableDOMError(result));437 }, this._page._timeoutSettings.timeout(options));438 }439 _tap(progress, options) {440 return this._retryPointerAction(progress, 'tap', true441 /* waitForEnabled */442 , point => this._page.touchscreen.tap(point.x, point.y), options);443 }444 async selectOption(metadata, elements, values, options) {445 const controller = new _progress.ProgressController(metadata, this);446 return controller.run(async progress => {447 const result = await this._selectOption(progress, elements, values, options);448 return throwRetargetableDOMError(result);449 }, this._page._timeoutSettings.timeout(options));450 }451 async _selectOption(progress, elements, values, options) {452 const optionsToSelect = [...elements, ...values];453 await progress.beforeInputAction(this);454 return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {455 progress.throwIfAborted(); // Avoid action that has side-effects.456 progress.log(' selecting specified option(s)');457 const poll = await this.evaluateHandleInUtility(([injected, node, {458 optionsToSelect,459 force460 }]) => {461 return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled'], force, injected.selectOptions.bind(injected, optionsToSelect));462 }, {463 optionsToSelect,464 force: options.force465 });466 if (poll === 'error:notconnected') return poll;467 const pollHandler = new InjectedScriptPollHandler(progress, poll);468 const result = await pollHandler.finishMaybeNotConnected();469 await this._page._doSlowMo();470 return result;471 });472 }473 async fill(metadata, value, options = {}) {474 const controller = new _progress.ProgressController(metadata, this);475 return controller.run(async progress => {476 const result = await this._fill(progress, value, options);477 assertDone(throwRetargetableDOMError(result));478 }, this._page._timeoutSettings.timeout(options));479 }480 async _fill(progress, value, options) {481 progress.log(`elementHandle.fill("${value}")`);482 await progress.beforeInputAction(this);483 return this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {484 progress.log(' waiting for element to be visible, enabled and editable');485 const poll = await this.evaluateHandleInUtility(([injected, node, {486 value,487 force488 }]) => {489 return injected.waitForElementStatesAndPerformAction(node, ['visible', 'enabled', 'editable'], force, injected.fill.bind(injected, value));490 }, {491 value,492 force: options.force493 });494 if (poll === 'error:notconnected') return poll;495 const pollHandler = new InjectedScriptPollHandler(progress, poll);496 const filled = await pollHandler.finishMaybeNotConnected();497 progress.throwIfAborted(); // Avoid action that has side-effects.498 if (filled === 'error:notconnected') return filled;499 progress.log(' element is visible, enabled and editable');500 if (filled === 'needsinput') {501 progress.throwIfAborted(); // Avoid action that has side-effects.502 if (value) await this._page.keyboard.insertText(value);else await this._page.keyboard.press('Delete');503 } else {504 assertDone(filled);505 }506 return 'done';507 }, 'input');508 }509 async selectText(metadata, options = {}) {510 const controller = new _progress.ProgressController(metadata, this);511 return controller.run(async progress => {512 progress.throwIfAborted(); // Avoid action that has side-effects.513 const poll = await this.evaluateHandleInUtility(([injected, node, force]) => {514 return injected.waitForElementStatesAndPerformAction(node, ['visible'], force, injected.selectText.bind(injected));515 }, options.force);516 const pollHandler = new InjectedScriptPollHandler(progress, throwRetargetableDOMError(poll));517 const result = await pollHandler.finishMaybeNotConnected();518 assertDone(throwRetargetableDOMError(result));519 }, this._page._timeoutSettings.timeout(options));520 }521 async setInputFiles(metadata, files, options) {522 const controller = new _progress.ProgressController(metadata, this);523 return controller.run(async progress => {524 const result = await this._setInputFiles(progress, files, options);525 return assertDone(throwRetargetableDOMError(result));526 }, this._page._timeoutSettings.timeout(options));527 }528 async _setInputFiles(progress, files, options) {529 for (const payload of files) {530 if (!payload.mimeType) payload.mimeType = mime.getType(payload.name) || 'application/octet-stream';531 }532 const retargeted = await this.evaluateHandleInUtility(([injected, node, multiple]) => {533 const element = injected.retarget(node, 'follow-label');534 if (!element) return 'error:notconnected';535 if (element.tagName !== 'INPUT') throw injected.createStacklessError('Node is not an HTMLInputElement');536 if (multiple && !element.multiple) throw injected.createStacklessError('Non-multiple file input can only accept single file');537 return element;538 }, files.length > 1);539 if (retargeted === 'error:notconnected') return retargeted;540 if (!retargeted._objectId) return retargeted.rawValue();541 await progress.beforeInputAction(this);542 await this._page._frameManager.waitForSignalsCreatedBy(progress, options.noWaitAfter, async () => {543 progress.throwIfAborted(); // Avoid action that has side-effects.544 await this._page._delegate.setInputFiles(retargeted, files);545 });546 await this._page._doSlowMo();547 return 'done';548 }549 async focus(metadata) {550 const controller = new _progress.ProgressController(metadata, this);...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createStacklessError } = require('playwright/lib/utils/stackTrace');2const stacklessError = createStacklessError('Error message');3console.log(stacklessError.stack);4 at Object.<anonymous> (C:\Users\user\test.js:5:30)5 at Module._compile (internal/modules/cjs/loader.js:1137:30)6 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)7 at Module.load (internal/modules/cjs/loader.js:985:32)8 at Function.Module._load (internal/modules/cjs/loader.js:878:14)9 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)

Full Screen

Using AI Code Generation

copy

Full Screen

1const { InternalError } = require('playwright/lib/utils/stackTrace');2const error = new InternalError('Test error');3console.log(error.stack);4 at Object.<anonymous> (/Users/username/playwright/test.js:3:13)5 at Module._compile (internal/modules/cjs/loader.js:1063:30)6 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)7 at Module.load (internal/modules/cjs/loader.js:928:32)8 at Function.Module._load (internal/modules/cjs/loader.js:769:14)9 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)10 at Object.<anonymous> (/Users/username/playwright/test.js:3:13)11 at Module._compile (internal/modules/cjs/loader.js:1063:30)12 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)13 at Module.load (internal/modules/cjs/loader.js:928:32)14 at Function.Module._load (internal/modules/cjs/loader.js:769:14)15 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)16 at Object.<anonymous> (/Users/username/playwright/test.js:3:13)17 at Module._compile (internal/modules/cjs/loader.js:1063:30)18 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)19 at Module.load (internal/modules/cjs/loader.js:928:32)20 at Function.Module._load (internal/modules/cjs/loader.js:769:14)21 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)22 at Object.<anonymous> (/Users/username/playwright/test.js:3:13)23 at Module._compile (internal/modules/cjs/loader.js:1063:30)24 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createStacklessError } = require('playwright/lib/utils/stackTrace');2const error = createStacklessError('My Error');3console.log(error);4const { createStacklessError } = require('playwright-test/lib/utils/stackTrace');5const error = createStacklessError('My Error');6console.log(error);7 at Object.<anonymous> (test.js:5:19)8 at Module._compile (internal/modules/cjs/loader.js:1063:30)9 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)10 at Module.load (internal/modules/cjs/loader.js:928:32)11 at Function.Module._load (internal/modules/cjs/loader.js:769:14)12 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)

Full Screen

Using AI Code Generation

copy

Full Screen

1const {createStacklessError} = require("playwright/lib/utils/stackTrace");2const error = createStacklessError(new Error("Test error"), "Test error");3console.log(error);4console.log(error.stack);5 at Object.<anonymous> (C:\Users\test\test.js:7:27)6 at Module._compile (internal/modules/cjs/loader.js:1063:30)7 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)8 at Module.load (internal/modules/cjs/loader.js:928:32)9 at Function.Module._load (internal/modules/cjs/loader.js:769:14)10 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)11 at Object.<anonymous> (C:\Users\test\test.js:7:27)12 at Object.<anonymous> (C:\Users\test\test.js:7:27)13 at Module._compile (internal/modules/cjs/loader.js:1063:30)14 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)15 at Module.load (internal/modules/cjs/loader.js:928:32)16 at Function.Module._load (internal/modules/cjs/loader.js:769:14)17 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createStacklessError } = require('playwright-core/lib/utils/stackTrace');2const err = createStacklessError('Custom Error');3console.log(err);4const { createStacklessError } = require('playwright-core/lib/utils/stackTrace');5const { test, expect } = require('@playwright/test');6test('Test', async ({ page }) => {7 const err = createStacklessError('Custom Error');8 expect(err).toBeTruthy();9});

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful