Best JavaScript code snippet using playwright-internal
backend.js
Source:backend.js
...2330}2331/**2332 * Get children from a component instance.2333 */2334function getInternalInstanceChildren(instance) {2335 if (instance.$children) {2336 return instance.$children;2337 }2338 if (Array.isArray(instance.subTree.children)) {2339 return instance.subTree.children.filter(vnode => !!vnode.component).map(vnode => vnode.component);2340 }2341 return [];2342}2343/**2344 * Check if an instance is qualified.2345 */2346function isQualified(instance) {2347 const name = shared_utils_1.classify(instance.name || util_1.getInstanceName(instance)).toLowerCase();2348 return name.indexOf(filter) > -1;2349}2350function flatten(items) {2351 return items.reduce((acc, item) => {2352 if (item instanceof Array)2353 acc.push(...flatten(item));2354 else if (item)2355 acc.push(item);2356 return acc;2357 }, []);2358}2359function captureChild(child) {2360 if (child.fnContext && !child.componentInstance) {2361 return capture(child);2362 }2363 else if (child.componentInstance) {2364 if (!util_1.isBeingDestroyed(child.componentInstance))2365 return capture(child.componentInstance);2366 }2367 else if (child.children) {2368 return flatten(child.children.map(captureChild));2369 }2370}2371/**2372 * Capture the meta information of an instance. (recursive)2373 */2374function capture(instance, index, list) {2375 if (instance.__VUE_DEVTOOLS_FUNCTIONAL_LEGACY__) {2376 instance = instance.vnode;2377 }2378 if (instance.$options && instance.$options.abstract && instance._vnode && instance._vnode.componentInstance) {2379 instance = instance._vnode.componentInstance;2380 }2381 // Functional component.2382 if (instance.fnContext && !instance.componentInstance) {2383 const contextUid = instance.fnContext.__VUE_DEVTOOLS_UID__;2384 let id = functionalIds.get(contextUid);2385 if (id == null) {2386 id = 0;2387 }2388 else {2389 id++;2390 }2391 functionalIds.set(contextUid, id);2392 const functionalId = contextUid + ':functional:' + id;2393 markFunctional(functionalId, instance);2394 const children = (instance.children ? instance.children.map(child => child.fnContext2395 ? captureChild(child)2396 : child.componentInstance2397 ? capture(child.componentInstance)2398 : undefined)2399 // router-view has both fnContext and componentInstance on vnode.2400 : instance.componentInstance ? [capture(instance.componentInstance)] : []).filter(Boolean);2401 return {2402 uid: functionalId,2403 id: functionalId,2404 tags: [2405 {2406 label: 'functional',2407 textColor: 0x555555,2408 backgroundColor: 0xeeeeee2409 }2410 ],2411 name: util_1.getInstanceName(instance),2412 renderKey: util_1.getRenderKey(instance.key),2413 children,2414 hasChildren: !!children.length,2415 inactive: false,2416 isFragment: false // TODO: Check what is it for.2417 };2418 }2419 // instance._uid is not reliable in devtools as there2420 // may be 2 roots with same _uid which causes unexpected2421 // behaviour2422 instance.__VUE_DEVTOOLS_UID__ = util_1.getUniqueId(instance);2423 // Dedupe2424 if (captureIds.has(instance.__VUE_DEVTOOLS_UID__)) {2425 return;2426 }2427 else {2428 captureIds.set(instance.__VUE_DEVTOOLS_UID__, undefined);2429 }2430 mark(instance);2431 const name = util_1.getInstanceName(instance);2432 const children = getInternalInstanceChildren(instance)2433 .filter(child => !util_1.isBeingDestroyed(child))2434 .map(capture)2435 .filter(Boolean);2436 const ret = {2437 uid: instance._uid,2438 id: instance.__VUE_DEVTOOLS_UID__,2439 name,2440 renderKey: util_1.getRenderKey(instance.$vnode ? instance.$vnode.key : null),2441 inactive: !!instance._inactive,2442 isFragment: !!instance._isFragment,2443 children,2444 hasChildren: !!children.length,2445 tags: [],2446 meta: {}2447 };2448 if (instance._vnode && instance._vnode.children) {2449 ret.children = ret.children.concat(flatten(instance._vnode.children.map(captureChild))2450 .filter(Boolean));2451 ret.hasChildren = !!ret.children.length;2452 }2453 // record screen position to ensure correct ordering2454 if ((!list || list.length > 1) && !instance._inactive) {2455 const rect = el_1.getInstanceOrVnodeRect(instance);2456 ret.positionTop = rect ? rect.top : Infinity;2457 }2458 else {2459 ret.positionTop = Infinity;2460 }2461 // check if instance is available in console2462 const consoleId = consoleBoundInstances.indexOf(instance.__VUE_DEVTOOLS_UID__);2463 ret.consoleId = consoleId > -1 ? '$vm' + consoleId : null;2464 // check router view2465 const isRouterView2 = instance.$vnode && instance.$vnode.data.routerView;2466 if (instance._routerView || isRouterView2) {2467 ret.isRouterView = true;2468 if (!instance._inactive && instance.$route) {2469 const matched = instance.$route.matched;2470 const depth = isRouterView22471 ? instance.$vnode.data.routerViewDepth2472 : instance._routerView.depth;2473 ret.meta.matchedRouteSegment =2474 matched &&2475 matched[depth] &&2476 (isRouterView2 ? matched[depth].path : matched[depth].handler.path);2477 }2478 ret.tags.push({2479 label: `router-view${ret.meta.matchedRouteSegment ? `: ${ret.meta.matchedRouteSegment}` : ''}`,2480 textColor: 0x000000,2481 backgroundColor: 0xff83442482 });2483 }2484 return ret;2485}2486/**2487 * Mark an instance as captured and store it in the instance map.2488 *2489 * @param {Vue} instance2490 */2491function mark(instance) {2492 const refId = instance.__VUE_DEVTOOLS_UID__;2493 if (!exports.instanceMap.has(refId)) {2494 exports.instanceMap.set(refId, instance);2495 appRecord.instanceMap.set(refId, instance);2496 instance.$on('hook:beforeDestroy', function () {2497 exports.instanceMap.delete(refId);2498 });2499 }2500}2501function markFunctional(id, vnode) {2502 const refId = vnode.fnContext.__VUE_DEVTOOLS_UID__;2503 if (!exports.functionalVnodeMap.has(refId)) {2504 exports.functionalVnodeMap.set(refId, {});2505 vnode.fnContext.$on('hook:beforeDestroy', function () {2506 exports.functionalVnodeMap.delete(refId);2507 });2508 }2509 exports.functionalVnodeMap.get(refId)[id] = vnode;2510 appRecord.instanceMap.set(id, {2511 __VUE_DEVTOOLS_UID__: id,2512 __VUE_DEVTOOLS_FUNCTIONAL_LEGACY__: true,2513 vnode2514 });2515}2516//# sourceMappingURL=tree.js.map2517/***/ }),2518/***/ 1247:2519/***/ ((__unused_webpack_module, exports, __webpack_require__) => {2520"use strict";2521Object.defineProperty(exports, "__esModule", ({ value: true }));2522exports.getUniqueId = exports.getRenderKey = exports.getInstanceName = exports.isBeingDestroyed = void 0;2523const shared_utils_1 = __webpack_require__(1942);2524function isBeingDestroyed(instance) {2525 return instance._isBeingDestroyed;2526}2527exports.isBeingDestroyed = isBeingDestroyed;2528/**2529 * Get the appropriate display name for an instance.2530 */2531function getInstanceName(instance) {2532 const name = shared_utils_1.getComponentName(instance.$options || instance.fnOptions || {});2533 if (name)2534 return name;2535 return instance.$root === instance2536 ? 'Root'2537 : 'Anonymous Component';2538}2539exports.getInstanceName = getInstanceName;2540function getRenderKey(value) {2541 if (value == null)2542 return;2543 const type = typeof value;2544 if (type === 'number') {2545 return value.toString();2546 }2547 else if (type === 'string') {2548 return `'${value}'`;2549 }2550 else if (Array.isArray(value)) {2551 return 'Array';2552 }2553 else {2554 return 'Object';2555 }2556}2557exports.getRenderKey = getRenderKey;2558/**2559 * Returns a devtools unique id for instance.2560 */2561function getUniqueId(instance) {2562 if (instance.__VUE_DEVTOOLS_UID__ != null)2563 return instance.__VUE_DEVTOOLS_UID__;2564 const rootVueId = instance.$root.__VUE_DEVTOOLS_ROOT_UID__;2565 return `${rootVueId}:${instance._uid}`;2566}2567exports.getUniqueId = getUniqueId;2568//# sourceMappingURL=util.js.map2569/***/ }),2570/***/ 5586:2571/***/ ((__unused_webpack_module, exports, __webpack_require__) => {2572"use strict";2573Object.defineProperty(exports, "__esModule", ({ value: true }));2574exports.wrapVueForEvents = void 0;2575const shared_utils_1 = __webpack_require__(1942);2576const internalRE = /^(?:pre-)?hook:/;2577function wrap(app, Vue, method, ctx) {2578 const original = Vue.prototype[method];2579 if (original) {2580 Vue.prototype[method] = function (...args) {2581 const res = original.apply(this, args);2582 logEvent(this, method, args[0], args.slice(1));2583 return res;2584 };2585 }2586 function logEvent(vm, type, eventName, payload) {2587 // The string check is important for compat with 1.x where the first2588 // argument may be an object instead of a string.2589 // this also ensures the event is only logged for direct $emit (source)2590 // instead of by $dispatch/$broadcast2591 if (typeof eventName === 'string' && !internalRE.test(eventName)) {2592 const instance = vm._self || vm;2593 ctx.hook.emit(shared_utils_1.HookEvents.COMPONENT_EMIT, app, instance, eventName, payload);2594 }2595 }2596}2597function wrapVueForEvents(app, Vue, ctx) {2598 ;2599 ['$emit', '$broadcast', '$dispatch'].forEach(method => {2600 wrap(app, Vue, method, ctx);2601 });2602}2603exports.wrapVueForEvents = wrapVueForEvents;2604//# sourceMappingURL=events.js.map2605/***/ }),2606/***/ 7167:2607/***/ ((__unused_webpack_module, exports, __webpack_require__) => {2608"use strict";2609Object.defineProperty(exports, "__esModule", ({ value: true }));2610exports.backend = void 0;2611const app_backend_api_1 = __webpack_require__(860);2612const shared_utils_1 = __webpack_require__(1942);2613const data_1 = __webpack_require__(7043);2614const el_1 = __webpack_require__(5030);2615const tree_1 = __webpack_require__(9606);2616const util_1 = __webpack_require__(1247);2617const events_1 = __webpack_require__(5586);2618const plugin_1 = __webpack_require__(6132);2619exports.backend = {2620 frameworkVersion: 2,2621 availableFeatures: [2622 app_backend_api_1.BuiltinBackendFeature.COMPONENTS,2623 app_backend_api_1.BuiltinBackendFeature.FLUSH2624 ],2625 setup(api) {2626 api.on.getAppRecordName(payload => {2627 if (payload.app.name) {2628 payload.name = payload.app.name;2629 }2630 });2631 api.on.getAppRootInstance(payload => {2632 payload.root = payload.app;2633 });2634 api.on.walkComponentTree((payload, ctx) => {2635 payload.componentTreeData = tree_1.walkTree(payload.componentInstance, payload.filter, ctx);2636 });2637 api.on.walkComponentParents((payload, ctx) => {2638 payload.parentInstances = tree_1.getComponentParents(payload.componentInstance, ctx);2639 });2640 api.on.inspectComponent(payload => {2641 injectToUtils();2642 payload.instanceData = data_1.getInstanceDetails(payload.componentInstance);2643 });2644 api.on.getComponentBounds(payload => {2645 payload.bounds = el_1.getInstanceOrVnodeRect(payload.componentInstance);2646 });2647 api.on.getComponentName(payload => {2648 const instance = payload.componentInstance;2649 payload.name = instance.fnContext ? shared_utils_1.getComponentName(instance.fnOptions) : util_1.getInstanceName(instance);2650 });2651 api.on.getElementComponent(payload => {2652 payload.componentInstance = el_1.findRelatedComponent(payload.element);2653 });2654 api.on.editComponentState(payload => {2655 data_1.editState(payload);2656 });2657 api.on.getComponentRootElements(payload => {2658 payload.rootElements = [payload.componentInstance.$el];2659 });2660 api.on.getComponentDevtoolsOptions(payload => {2661 payload.options = payload.componentInstance.$options.devtools;2662 });2663 api.on.getComponentInstances(() => {2664 console.warn('on.getComponentInstances is not implemented for Vue 2');2665 });2666 },2667 setupApp(api, appRecord) {2668 injectToUtils();2669 const { Vue } = appRecord.options.meta;2670 const app = appRecord.options.app;2671 events_1.wrapVueForEvents(app, Vue, api.ctx);2672 plugin_1.setupPlugin(api, app);2673 }2674};2675function injectToUtils() {2676 shared_utils_1.backendInjections.getCustomInstanceDetails = data_1.getCustomInstanceDetails;2677 shared_utils_1.backendInjections.instanceMap = tree_1.instanceMap;2678}2679//# sourceMappingURL=index.js.map2680/***/ }),2681/***/ 6132:2682/***/ ((__unused_webpack_module, exports, __webpack_require__) => {2683"use strict";2684Object.defineProperty(exports, "__esModule", ({ value: true }));2685exports.setupPlugin = void 0;2686const devtools_api_1 = __webpack_require__(2296);2687const shared_utils_1 = __webpack_require__(1942);2688let actionId = 0;2689function setupPlugin(api, app) {2690 const ROUTER_INSPECTOR_ID = 'vue2-router-inspector';2691 const ROUTER_CHANGES_LAYER_ID = 'vue2-router-changes';2692 const VUEX_INSPECTOR_ID = 'vue2-vuex-inspector';2693 const VUEX_MUTATIONS_ID = 'vue2-vuex-mutations';2694 const VUEX_ACTIONS_ID = 'vue2-vuex-actions';2695 devtools_api_1.setupDevtoolsPlugin({2696 app,2697 id: 'org.vuejs.vue2-internal',2698 label: 'Vue 2',2699 homepage: 'https://vuejs.org/',2700 logo: 'https://vuejs.org/images/icons/favicon-96x96.png'2701 }, api => {2702 // Vue Router2703 if (app.$router) {2704 const router = app.$router;2705 // Inspector2706 api.addInspector({2707 id: ROUTER_INSPECTOR_ID,2708 label: 'Routes',2709 icon: 'book',2710 treeFilterPlaceholder: 'Search routes'2711 });2712 api.on.getInspectorTree(payload => {2713 if (payload.app === app && payload.inspectorId === ROUTER_INSPECTOR_ID) {2714 payload.rootNodes = router.options.routes.map(route => formatRouteNode(router, route, '', payload.filter)).filter(Boolean);2715 }2716 });2717 api.on.getInspectorState(payload => {2718 if (payload.app === app && payload.inspectorId === ROUTER_INSPECTOR_ID) {2719 const route = router.matcher.getRoutes().find(r => getPathId(r) === payload.nodeId);2720 if (route) {2721 payload.state = {2722 options: formatRouteData(route)2723 };2724 }2725 }2726 });2727 // Timeline2728 api.addTimelineLayer({2729 id: ROUTER_CHANGES_LAYER_ID,2730 label: 'Router Navigations',2731 color: 0x40a8c42732 });2733 router.afterEach((to, from) => {2734 api.addTimelineEvent({2735 layerId: ROUTER_CHANGES_LAYER_ID,2736 event: {2737 time: Date.now(),2738 title: to.path,2739 data: {2740 from,2741 to2742 }2743 }2744 });2745 api.sendInspectorTree(ROUTER_INSPECTOR_ID);2746 });2747 }2748 // Vuex2749 if (app.$store) {2750 const store = app.$store;2751 api.addInspector({2752 id: VUEX_INSPECTOR_ID,2753 label: 'Vuex',2754 icon: 'storage',2755 treeFilterPlaceholder: 'Filter stores...'2756 });2757 api.on.getInspectorTree((payload) => {2758 if (payload.app === app && payload.inspectorId === VUEX_INSPECTOR_ID) {2759 if (payload.filter) {2760 const nodes = [];2761 flattenStoreForInspectorTree(nodes, store._modules.root, payload.filter, '');2762 payload.rootNodes = nodes;2763 }2764 else {2765 payload.rootNodes = [2766 formatStoreForInspectorTree(store._modules.root, '')2767 ];2768 }2769 }2770 });2771 api.on.getInspectorState((payload) => {2772 if (payload.app === app && payload.inspectorId === VUEX_INSPECTOR_ID) {2773 const modulePath = payload.nodeId;2774 const module = getStoreModule(store._modules, modulePath);2775 // Access the getters prop to init getters cache (which is lazy)2776 // eslint-disable-next-line no-unused-expressions2777 module.context.getters;2778 payload.state = formatStoreForInspectorState(module, store._makeLocalGettersCache, modulePath);2779 }2780 });2781 api.addTimelineLayer({2782 id: VUEX_MUTATIONS_ID,2783 label: 'Vuex Mutations',2784 color: LIME_5002785 });2786 api.addTimelineLayer({2787 id: VUEX_ACTIONS_ID,2788 label: 'Vuex Actions',2789 color: LIME_5002790 });2791 store.subscribe((mutation, state) => {2792 api.sendInspectorState(VUEX_INSPECTOR_ID);2793 const data = {};2794 if (mutation.payload) {2795 data.payload = mutation.payload;2796 }2797 data.state = state;2798 api.addTimelineEvent({2799 layerId: VUEX_MUTATIONS_ID,2800 event: {2801 time: Date.now(),2802 title: mutation.type,2803 data2804 }2805 });2806 }, { prepend: true });2807 store.subscribeAction({2808 before: (action, state) => {2809 const data = {};2810 if (action.payload) {2811 data.payload = action.payload;2812 }2813 action._id = actionId++;2814 action._time = Date.now();2815 data.state = state;2816 api.addTimelineEvent({2817 layerId: VUEX_ACTIONS_ID,2818 event: {2819 time: action._time,2820 title: action.type,2821 groupId: action._id,2822 subtitle: 'start',2823 data2824 }2825 });2826 },2827 after: (action, state) => {2828 const data = {};2829 const duration = Date.now() - action._time;2830 data.duration = {2831 _custom: {2832 type: 'duration',2833 display: `${duration}ms`,2834 tooltip: 'Action duration',2835 value: duration2836 }2837 };2838 if (action.payload) {2839 data.payload = action.payload;2840 }2841 data.state = state;2842 api.addTimelineEvent({2843 layerId: VUEX_ACTIONS_ID,2844 event: {2845 time: Date.now(),2846 title: action.type,2847 groupId: action._id,2848 subtitle: 'end',2849 data2850 }2851 });2852 }2853 }, { prepend: true });2854 }2855 });2856}2857exports.setupPlugin = setupPlugin;2858/**2859 * Extracted from tailwind palette2860 */2861const BLUE_600 = 0x2563eb;2862const LIME_500 = 0x84cc16;2863const CYAN_400 = 0x22d3ee;2864const ORANGE_400 = 0xfb923c;2865const WHITE = 0xffffff;2866const DARK = 0x666666;2867function formatRouteNode(router, route, parentPath, filter) {2868 var _a, _b;2869 const node = {2870 id: parentPath + route.path,2871 label: route.path,2872 children: (_a = route.children) === null || _a === void 0 ? void 0 : _a.map(child => formatRouteNode(router, child, route.path, filter)).filter(Boolean),2873 tags: []2874 };2875 if (filter && !node.id.includes(filter) && !((_b = node.children) === null || _b === void 0 ? void 0 : _b.length))2876 return null;2877 if (route.name != null) {2878 node.tags.push({2879 label: String(route.name),2880 textColor: 0,2881 backgroundColor: CYAN_4002882 });2883 }2884 if (route.alias != null) {2885 node.tags.push({2886 label: 'alias',2887 textColor: 0,2888 backgroundColor: ORANGE_4002889 });2890 }2891 const currentPath = router.currentRoute.matched.reduce((p, m) => p + m.path, '');2892 if (node.id === currentPath) {2893 node.tags.push({2894 label: 'active',2895 textColor: WHITE,2896 backgroundColor: BLUE_6002897 });2898 }2899 if (route.redirect) {2900 node.tags.push({2901 label: 'redirect: ' +2902 (typeof route.redirect === 'string' ? route.redirect : 'Object'),2903 textColor: WHITE,2904 backgroundColor: DARK2905 });2906 }2907 return node;2908}2909function formatRouteData(route) {2910 const data = [];2911 data.push({ key: 'path', value: route.path });2912 if (route.redirect) {2913 data.push({ key: 'redirect', value: route.redirect });2914 }2915 if (route.alias) {2916 data.push({ key: 'alias', value: route.alias });2917 }2918 if (route.props) {2919 data.push({ key: 'props', value: route.props });2920 }2921 if (route.name && route.name != null) {2922 data.push({ key: 'name', value: route.name });2923 }2924 if (route.component) {2925 const component = {};2926 // if (route.component.__file) {2927 // component.file = route.component.__file2928 // }2929 if (route.component.template) {2930 component.template = route.component.template;2931 }2932 if (route.component.props) {2933 component.props = route.component.props;2934 }2935 if (!shared_utils_1.isEmptyObject(component)) {2936 data.push({ key: 'component', value: component });2937 }2938 }2939 return data;2940}2941function getPathId(routeMatcher) {2942 let path = routeMatcher.path;2943 if (routeMatcher.parent) {2944 path = getPathId(routeMatcher.parent) + path;2945 }2946 return path;2947}2948const TAG_NAMESPACED = {2949 label: 'namespaced',2950 textColor: WHITE,2951 backgroundColor: DARK2952};2953function formatStoreForInspectorTree(module, path) {2954 return {2955 id: path || 'root',2956 // all modules end with a `/`, we want the last segment only2957 // cart/ -> cart2958 // nested/cart/ -> cart2959 label: extractNameFromPath(path),2960 tags: module.namespaced ? [TAG_NAMESPACED] : [],2961 children: Object.keys(module._children).map((moduleName) => formatStoreForInspectorTree(module._children[moduleName], path + moduleName + '/'))2962 };2963}2964function flattenStoreForInspectorTree(result, module, filter, path) {2965 if (path.includes(filter)) {2966 result.push({2967 id: path || 'root',2968 label: path.endsWith('/') ? path.slice(0, path.length - 1) : path || 'Root',2969 tags: module.namespaced ? [TAG_NAMESPACED] : []2970 });2971 }2972 Object.keys(module._children).forEach(moduleName => {2973 flattenStoreForInspectorTree(result, module._children[moduleName], filter, path + moduleName + '/');2974 });2975}2976function extractNameFromPath(path) {2977 return path && path !== 'root' ? path.split('/').slice(-2, -1)[0] : 'Root';2978}2979function formatStoreForInspectorState(module, getters, path) {2980 getters = path === 'root' ? getters : getters[path];2981 const gettersKeys = Object.keys(getters);2982 const storeState = {2983 state: Object.keys(module.state).map((key) => ({2984 key,2985 editable: true,2986 value: module.state[key]2987 }))2988 };2989 if (gettersKeys.length) {2990 storeState.getters = gettersKeys.map((key) => ({2991 key: key.endsWith('/') ? extractNameFromPath(key) : key,2992 editable: false,2993 value: getters[key]2994 }));2995 }2996 return storeState;2997}2998function getStoreModule(moduleMap, path) {2999 const names = path.split('/').filter((n) => n);3000 return names.reduce((module, moduleName, i) => {3001 const child = module[moduleName];3002 if (!child) {3003 throw new Error(`Missing module "${moduleName}" for path "${path}".`);3004 }3005 return i === names.length - 1 ? child : child._children;3006 }, path === 'root' ? moduleMap : moduleMap.root._children);3007}3008//# sourceMappingURL=plugin.js.map3009/***/ }),3010/***/ 5467:3011/***/ (function(__unused_webpack_module, exports, __webpack_require__) {3012"use strict";3013var __importDefault = (this && this.__importDefault) || function (mod) {3014 return (mod && mod.__esModule) ? mod : { "default": mod };3015};3016Object.defineProperty(exports, "__esModule", ({ value: true }));3017exports.getCustomInstanceDetails = exports.editState = exports.getInstanceDetails = void 0;3018const util_1 = __webpack_require__(1122);3019const shared_utils_1 = __webpack_require__(1942);3020const shared_data_1 = __importDefault(__webpack_require__(796));3021/**3022 * Get the detailed information of an inspected instance.3023 */3024async function getInstanceDetails(instance, ctx) {3025 var _a;3026 return {3027 id: util_1.getUniqueComponentId(instance, ctx),3028 name: util_1.getInstanceName(instance),3029 file: (_a = instance.type) === null || _a === void 0 ? void 0 : _a.__file,3030 state: await getInstanceState(instance)3031 };3032}3033exports.getInstanceDetails = getInstanceDetails;3034async function getInstanceState(instance) {3035 return processProps(instance).concat(processState(instance), processSetupState(instance), processComputed(instance), processAttrs(instance), processProvide(instance), processInject(instance), processRefs(instance));3036}3037/**3038 * Process the props of an instance.3039 * Make sure return a plain object because window.postMessage()3040 * will throw an Error if the passed object contains Functions.3041 *3042 * @param {Vue} instance3043 * @return {Array}3044 */3045function processProps(instance) {3046 const propsData = [];3047 const propDefinitions = instance.type.props;3048 for (let key in instance.props) {3049 const propDefinition = propDefinitions ? propDefinitions[key] : null;3050 key = shared_utils_1.camelize(key);3051 propsData.push({3052 type: 'props',3053 key,3054 value: instance.props[key],3055 meta: propDefinition ? {3056 type: propDefinition.type ? getPropType(propDefinition.type) : 'any',3057 required: !!propDefinition.required,3058 ...propDefinition.default != null ? {3059 default: propDefinition.default.toString()3060 } : {}3061 } : {3062 type: 'invalid'3063 },3064 editable: shared_data_1.default.editableProps3065 });3066 }3067 return propsData;3068}3069const fnTypeRE = /^(?:function|class) (\w+)/;3070/**3071 * Convert prop type constructor to string.3072 */3073function getPropType(type) {3074 const match = type.toString().match(fnTypeRE);3075 return typeof type === 'function'3076 ? (match && match[1]) || 'any'3077 : 'any';3078}3079/**3080 * Process state, filtering out props and "clean" the result3081 * with a JSON dance. This removes functions which can cause3082 * errors during structured clone used by window.postMessage.3083 *3084 * @param {Vue} instance3085 * @return {Array}3086 */3087function processState(instance) {3088 const type = instance.type;3089 const props = type.props;3090 const getters = type.vuex &&3091 type.vuex.getters;3092 const computedDefs = type.computed;3093 const data = {3094 ...instance.data,3095 ...instance.renderContext3096 };3097 return Object.keys(data)3098 .filter(key => (!(props && key in props) &&3099 !(getters && key in getters) &&3100 !(computedDefs && key in computedDefs)))3101 .map(key => ({3102 key,3103 type: 'data',3104 value: data[key],3105 editable: true3106 }));3107}3108function processSetupState(instance) {3109 const raw = instance.devtoolsRawSetupState || {};3110 return Object.keys(instance.setupState)3111 .map(key => ({3112 key,3113 type: 'setup',3114 value: instance.setupState[key],3115 ...getSetupStateExtra(raw[key])3116 }));3117}3118function getSetupStateExtra(raw) {3119 if (!raw)3120 return {};3121 const info = getSetupStateInfo(raw);3122 const objectType = info.computed ? 'Computed' : info.ref ? 'Ref' : info.reactive ? 'Reactive' : null;3123 return {3124 ...objectType ? { objectType } : {},3125 ...raw.effect ? { raw: raw.effect.raw.toString() } : {},3126 editable: (info.ref || info.computed || info.reactive) && !info.readonly3127 };3128}3129function isRef(raw) {3130 return !!raw.__v_isRef;3131}3132function isComputed(raw) {3133 return isRef(raw) && !!raw.effect;3134}3135function isReactive(raw) {3136 return !!raw.__v_isReactive;3137}3138function isReadOnly(raw) {3139 return !!raw.__v_isReadonly;3140}3141function getSetupStateInfo(raw) {3142 return {3143 ref: isRef(raw),3144 computed: isComputed(raw),3145 reactive: isReactive(raw),3146 readonly: isReadOnly(raw)3147 };3148}3149/**3150 * Process the computed properties of an instance.3151 *3152 * @param {Vue} instance3153 * @return {Array}3154 */3155function processComputed(instance) {3156 const type = instance.type;3157 const computed = [];3158 const defs = type.computed || {};3159 // use for...in here because if 'computed' is not defined3160 // on component, computed properties will be placed in prototype3161 // and Object.keys does not include3162 // properties from object's prototype3163 for (const key in defs) {3164 const def = defs[key];3165 const type = typeof def === 'function' && def.vuex3166 ? 'vuex bindings'3167 : 'computed';3168 // use try ... catch here because some computed properties may3169 // throw error during its evaluation3170 let computedProp = null;3171 try {3172 computedProp = {3173 type,3174 key,3175 value: instance.proxy[key],3176 editable: typeof def.set === 'function'3177 };3178 }3179 catch (e) {3180 computedProp = {3181 type,3182 key,3183 value: '(error during evaluation)'3184 };3185 }3186 computed.push(computedProp);3187 }3188 return computed;3189}3190function processAttrs(instance) {3191 return Object.keys(instance.attrs)3192 .map(key => ({3193 type: 'attrs',3194 key,3195 value: instance.attrs[key]3196 }));3197}3198function processProvide(instance) {3199 return Object.keys(instance.provides)3200 .map(key => ({3201 type: 'provided',3202 key,3203 value: instance.provides[key]3204 }));3205}3206function processInject(instance) {3207 if (!instance.type || !instance.type.inject)3208 return [];3209 let keys = [];3210 if (Array.isArray(instance.type.inject)) {3211 keys = instance.type.inject.map(key => ({3212 key,3213 originalKey: key3214 }));3215 }3216 else {3217 keys = Object.keys(instance.type.inject).map(key => {3218 const value = instance.type.inject[key];3219 let originalKey;3220 if (typeof value === 'string') {3221 originalKey = value;3222 }3223 else {3224 originalKey = value.from;3225 }3226 return {3227 key,3228 originalKey3229 };3230 });3231 }3232 return keys.map(({ key, originalKey }) => ({3233 type: 'injected',3234 key: originalKey && key !== originalKey ? `${originalKey} â ${key}` : key,3235 value: instance.ctx[key]3236 }));3237}3238function processRefs(instance) {3239 return Object.keys(instance.refs)3240 .map(key => ({3241 type: 'refs',3242 key,3243 value: instance.refs[key]3244 }));3245}3246function editState({ componentInstance, path, state }, ctx) {3247 let target;3248 const targetPath = path.slice();3249 if (Object.keys(componentInstance.props).includes(path[0])) {3250 // Props3251 target = componentInstance.props;3252 }3253 else if (Object.keys(componentInstance.devtoolsRawSetupState).includes(path[0])) {3254 // Setup3255 target = componentInstance.devtoolsRawSetupState;3256 const currentValue = shared_utils_1.get(componentInstance.devtoolsRawSetupState, path);3257 if (currentValue != null) {3258 const info = getSetupStateInfo(currentValue);3259 if (info.readonly)3260 return;3261 if (info.ref) {3262 targetPath.splice(1, 0, 'value');3263 }3264 }3265 }3266 else {3267 target = componentInstance.proxy;3268 }3269 if (target && targetPath) {3270 shared_utils_1.set(target, targetPath, 'value' in state ? state.value : undefined, (obj, field, value) => {3271 if (state.remove || state.newKey) {3272 if (Array.isArray(obj)) {3273 obj.splice(field, 1);3274 }3275 else {3276 delete obj[field];3277 }3278 }3279 if (!state.remove) {3280 obj[state.newKey || field] = value;3281 }3282 });3283 }3284}3285exports.editState = editState;3286function reduceStateList(list) {3287 if (!list.length) {3288 return undefined;3289 }3290 return list.reduce((map, item) => {3291 const key = item.type || 'data';3292 const obj = map[key] = map[key] || {};3293 obj[item.key] = item.value;3294 return map;3295 }, {});3296}3297function getCustomInstanceDetails(instance) {3298 const state = getInstanceState(instance);3299 return {3300 _custom: {3301 type: 'component',3302 id: instance.__VUE_DEVTOOLS_UID__,3303 display: util_1.getInstanceName(instance),3304 tooltip: 'Component instance',3305 value: reduceStateList(state),3306 fields: {3307 abstract: true3308 }3309 }3310 };3311}3312exports.getCustomInstanceDetails = getCustomInstanceDetails;3313//# sourceMappingURL=data.js.map3314/***/ }),3315/***/ 4644:3316/***/ ((__unused_webpack_module, exports, __webpack_require__) => {3317"use strict";3318Object.defineProperty(exports, "__esModule", ({ value: true }));3319exports.getInstanceOrVnodeRect = exports.getRootElementsFromComponentInstance = exports.getComponentInstanceFromElement = void 0;3320const shared_utils_1 = __webpack_require__(1942);3321const util_1 = __webpack_require__(1122);3322function getComponentInstanceFromElement(element) {3323 return element.__vueParentComponent;3324}3325exports.getComponentInstanceFromElement = getComponentInstanceFromElement;3326function getRootElementsFromComponentInstance(instance) {3327 if (util_1.isFragment(instance)) {3328 return getFragmentRootElements(instance.subTree);3329 }3330 return [instance.subTree.el];3331}3332exports.getRootElementsFromComponentInstance = getRootElementsFromComponentInstance;3333function getFragmentRootElements(vnode) {3334 if (!vnode.children)3335 return [];3336 const list = [];3337 for (let i = 0, l = vnode.children.length; i < l; i++) {3338 const childVnode = vnode.children[i];3339 if (childVnode.component) {3340 list.push(...getRootElementsFromComponentInstance(childVnode.component));3341 }3342 else if (childVnode.el) {3343 list.push(childVnode.el);3344 }3345 }3346 return list;3347}3348/**3349 * Get the client rect for an instance.3350 *3351 * @param {Vue|Vnode} instance3352 * @return {Object}3353 */3354function getInstanceOrVnodeRect(instance) {3355 const el = instance.subTree.el;3356 if (!shared_utils_1.isBrowser) {3357 // @TODO: Find position from instance or a vnode (for functional components).3358 return;3359 }3360 if (!shared_utils_1.inDoc(el)) {3361 return;3362 }3363 if (util_1.isFragment(instance)) {3364 return getFragmentRect(instance.subTree);3365 }3366 else if (el.nodeType === 1) {3367 return el.getBoundingClientRect();3368 }3369}3370exports.getInstanceOrVnodeRect = getInstanceOrVnodeRect;3371function createRect() {3372 const rect = {3373 top: 0,3374 bottom: 0,3375 left: 0,3376 right: 0,3377 get width() { return rect.right - rect.left; },3378 get height() { return rect.bottom - rect.top; }3379 };3380 return rect;3381}3382function mergeRects(a, b) {3383 if (!a.top || b.top < a.top) {3384 a.top = b.top;3385 }3386 if (!a.bottom || b.bottom > a.bottom) {3387 a.bottom = b.bottom;3388 }3389 if (!a.left || b.left < a.left) {3390 a.left = b.left;3391 }3392 if (!a.right || b.right > a.right) {3393 a.right = b.right;3394 }3395}3396let range;3397/**3398 * Get the bounding rect for a text node using a Range.3399 *3400 * @param {Text} node3401 * @return {Rect}3402 */3403function getTextRect(node) {3404 if (!shared_utils_1.isBrowser)3405 return;3406 if (!range)3407 range = document.createRange();3408 range.selectNode(node);3409 return range.getBoundingClientRect();3410}3411function getFragmentRect(vnode) {3412 const rect = createRect();3413 if (!vnode.children)3414 return rect;3415 for (let i = 0, l = vnode.children.length; i < l; i++) {3416 const childVnode = vnode.children[i];3417 let childRect;3418 if (childVnode.component) {3419 childRect = getInstanceOrVnodeRect(childVnode.component);3420 }3421 else if (childVnode.el) {3422 const el = childVnode.el;3423 if (el.nodeType === 1 || el.getBoundingClientRect) {3424 childRect = el.getBoundingClientRect();3425 }3426 else if (el.nodeType === 3 && el.data.trim()) {3427 childRect = getTextRect(el);3428 }3429 }3430 if (childRect) {3431 mergeRects(rect, childRect);3432 }3433 }3434 return rect;3435}3436//# sourceMappingURL=el.js.map3437/***/ }),3438/***/ 2259:3439/***/ ((__unused_webpack_module, exports, __webpack_require__) => {3440"use strict";3441Object.defineProperty(exports, "__esModule", ({ value: true }));3442exports.ComponentFilter = void 0;3443const shared_utils_1 = __webpack_require__(1942);3444const util_1 = __webpack_require__(1122);3445class ComponentFilter {3446 constructor(filter) {3447 this.filter = filter || '';3448 }3449 /**3450 * Check if an instance is qualified.3451 *3452 * @param {Vue|Vnode} instance3453 * @return {Boolean}3454 */3455 isQualified(instance) {3456 const name = shared_utils_1.classify(instance.name || util_1.getInstanceName(instance)).toLowerCase();3457 return name.indexOf(this.filter) > -1;3458 }3459}3460exports.ComponentFilter = ComponentFilter;3461//# sourceMappingURL=filter.js.map3462/***/ }),3463/***/ 8333:3464/***/ ((__unused_webpack_module, exports, __webpack_require__) => {3465"use strict";3466Object.defineProperty(exports, "__esModule", ({ value: true }));3467exports.ComponentWalker = void 0;3468const util_1 = __webpack_require__(1122);3469const filter_1 = __webpack_require__(2259);3470const el_1 = __webpack_require__(4644);3471class ComponentWalker {3472 constructor(maxDepth, filter, ctx) {3473 this.ctx = ctx;3474 this.maxDepth = maxDepth;3475 this.componentFilter = new filter_1.ComponentFilter(filter);3476 }3477 getComponentTree(instance) {3478 this.captureIds = new Map();3479 return this.findQualifiedChildren(instance, 0);3480 }3481 getComponentParents(instance) {3482 this.captureIds = new Map();3483 const parents = [];3484 this.captureId(instance);3485 let parent = instance;3486 while ((parent = parent.parent)) {3487 this.captureId(parent);3488 parents.push(parent);3489 }3490 return parents;3491 }3492 /**3493 * Find qualified children from a single instance.3494 * If the instance itself is qualified, just return itself.3495 * This is ok because [].concat works in both cases.3496 *3497 * @param {Vue|Vnode} instance3498 * @return {Vue|Array}3499 */3500 async findQualifiedChildren(instance, depth) {3501 var _a;3502 if (this.componentFilter.isQualified(instance) && !((_a = instance.type.devtools) === null || _a === void 0 ? void 0 : _a.hide)) {3503 return [await this.capture(instance, null, depth)];3504 }3505 else if (instance.subTree) {3506 // TODO functional components3507 return this.findQualifiedChildrenFromList(this.getInternalInstanceChildren(instance.subTree), depth);3508 }3509 else {3510 return [];3511 }3512 }3513 /**3514 * Iterate through an array of instances and flatten it into3515 * an array of qualified instances. This is a depth-first3516 * traversal - e.g. if an instance is not matched, we will3517 * recursively go deeper until a qualified child is found.3518 *3519 * @param {Array} instances3520 * @return {Array}3521 */3522 async findQualifiedChildrenFromList(instances, depth) {3523 instances = instances3524 .filter(child => { var _a; return !util_1.isBeingDestroyed(child) && !((_a = child.type.devtools) === null || _a === void 0 ? void 0 : _a.hide); });3525 if (!this.componentFilter.filter) {3526 return Promise.all(instances.map((child, index, list) => this.capture(child, list, depth)));3527 }3528 else {3529 return Array.prototype.concat.apply([], await Promise.all(instances.map(i => this.findQualifiedChildren(i, depth))));3530 }3531 }3532 /**3533 * Get children from a component instance.3534 */3535 getInternalInstanceChildren(subTree) {3536 const list = [];3537 if (subTree.component) {3538 list.push(subTree.component);3539 }3540 if (subTree.suspense) {3541 list.push(...this.getInternalInstanceChildren(subTree.suspense.activeBranch));3542 }3543 if (Array.isArray(subTree.children)) {3544 subTree.children.forEach(childSubTree => {3545 if (childSubTree.component) {3546 list.push(childSubTree.component);3547 }3548 else {3549 list.push(...this.getInternalInstanceChildren(childSubTree));3550 }3551 });3552 }3553 return list.filter(child => { var _a; return !util_1.isBeingDestroyed(child) && !((_a = child.type.devtools) === null || _a === void 0 ? void 0 : _a.hide); });3554 }3555 captureId(instance) {3556 // instance.uid is not reliable in devtools as there3557 // may be 2 roots with same uid which causes unexpected3558 // behaviour3559 const id = instance.__VUE_DEVTOOLS_UID__ != null ? instance.__VUE_DEVTOOLS_UID__ : util_1.getUniqueComponentId(instance, this.ctx);3560 instance.__VUE_DEVTOOLS_UID__ = id;3561 // Dedupe3562 if (this.captureIds.has(id)) {3563 return;3564 }3565 else {3566 this.captureIds.set(id, undefined);3567 }3568 this.mark(instance);3569 return id;3570 }3571 /**3572 * Capture the meta information of an instance. (recursive)3573 *3574 * @param {Vue} instance3575 * @return {Object}3576 */3577 async capture(instance, list, depth) {3578 const id = this.captureId(instance);3579 const name = util_1.getInstanceName(instance);3580 const children = this.getInternalInstanceChildren(instance.subTree)3581 .filter(child => !util_1.isBeingDestroyed(child));3582 const treeNode = {3583 uid: instance.uid,3584 id,3585 name,3586 renderKey: util_1.getRenderKey(instance.vnode ? instance.vnode.key : null),3587 inactive: !!instance.isDeactivated,3588 hasChildren: !!children.length,3589 children: [],3590 isFragment: util_1.isFragment(instance),3591 tags: []3592 };3593 // capture children3594 if (depth < this.maxDepth) {...
Using AI Code Generation
1const { getInternalInstanceChildren } = require('playwright/lib/server/dom');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const internalInstance = await page._delegate._mainFrame._context._context._internalObject;8 const children = getInternalInstanceChildren(internalInstance);9 console.log(children);10 await browser.close();11})();12[ { _guid: '0x1',13 _objectId: '{"injectedScriptId":1,"id":1}',14 { description: 'HTMLDocument',15 type: 'object' },16 { description: 'HTMLDocument',17 type: 'object' },18 _internalType: 'document' },19 { _guid: '0x2',20 _objectId: '{"injectedScriptId":1,"id":2}',21 { description: 'HTMLHtmlElement',22 type: 'object' },23 { description: 'HTMLHtmlElement',24 type: 'object' },25 _internalType: 'node' },26 { _guid: '0x3',27 _objectId: '{"injectedScriptId":1,"id":3}',28 { description: 'HTMLHeadElement',29 type: 'object' },30 { description: 'HTMLHeadElement',
Using AI Code Generation
1const { getInternalInstanceChildren } = require('playwright/lib/server/dom');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const internalInstance = await page._mainFrame._page._delegate._document._internalDocument._internalInstance;8 const children = getInternalInstanceChildren(internalInstance);9 console.log(children);10 await browser.close();11})();12[ { _internalNode: { _internalInstance: [Circular] }, _internalParent: null },13 { _internalNode: { _internalInstance: [Circular] }, _internalParent: null } ]
Using AI Code Generation
1const { getInternalInstanceChildren } = require('playwright/lib/client/page');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 const internalChildren = await getInternalInstanceChildren(page);7 console.log(internalChildren);8 await browser.close();9})();10[ {11 _initializer: {12 _initializer: {13 _initializer: {14 _initializer: {15 _initializer: {16 _initializer: {17 _initializer: {18 _initializer: {19 _initializer: {20 _initializer: {21 _initializer: {22 _initializer: {23 _initializer: {24 _initializer: {25 _initializer: {26 _initializer: {27 _initializer: {28 _initializer: {29 _initializer: {30 _initializer: {31 _initializer: {32 _initializer: {33 _initializer: {34 _initializer: {35 _initializer: {36 _initializer: {
Using AI Code Generation
1const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');2const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');3const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');4const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');5const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');6const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');7const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');8const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');9const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');10const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');11const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');12const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');13const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');14const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');15const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');16const { getInternalInstanceChildren } = require('playwright/lib/server/dom.js');
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const internal = await page._mainFrame._getInternalInstance();7 const children = await internal.getInternalInstanceChildren();8 console.log(children);9 await browser.close();10})();11 {12 _page: Page {13 _pageBindings: Map(0) {},14 _ownedContexts: Set(0) {},15 _ownedFrames: Set(1) { [Frame] },16 _timeoutSettings: TimeoutSettings { _defaultNavigationTimeout: 30000 },17 _workers: Set(0) {},18 _routes: Map(0) {},19 _viewportSize: { width: 1280, height: 720 },20 _defaultBrowserContext: BrowserContext {21 _ownedPages: Set(1) { [Circular] },22 _timeoutSettings: TimeoutSettings { _defaultNavigationTimeout: 30000 },23 _routes: Map(0) {},
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch({ headless: false });4 const page = await browser.newPage();5 const element = await page.$('text=Get Started');6 const internalElement = await element._getInternalInstance();7 const internalChildren = await internalElement._getInternalInstanceChildren();8 console.log(internalChildren);9})();
Using AI Code Generation
1const { getInternalInstanceChildren } = require('playwright/lib/server/dom');2const { Page } = require('playwright/lib/server/page');3const { ElementHandle } = require('playwright/lib/server/dom');4const { getInternalInstanceChildren } = require('playwright/lib/server/dom');5const { Page } = require('playwright/lib/server/page');6const { ElementHandle } = require('playwright/lib/server/dom');7const { getInternalInstanceChildren } = require('playwright/lib/server/dom');8const { Page } = require('playwright/lib/server/page');9const { ElementHandle } = require('playwright/lib/server/dom');10const { getInternalInstanceChildren } = require('playwright/lib/server/dom');11const { Page } = require('playwright/lib/server/page');12const { ElementHandle } = require('playwright/lib/server/dom');13const { getInternalInstanceChildren } = require('playwright/lib/server/dom');14const { Page } = require('playwright/lib/server/page');15const { ElementHandle } = require('playwright/lib/server/dom');16const { getInternalInstanceChildren } = require('playwright/lib/server/dom');17const { Page } = require('playwright/lib/server/page');18const { ElementHandle } = require('playwright/lib/server/dom');19const { getInternalInstanceChildren } = require('playwright/lib/server/dom');20const { Page } = require('playwright/lib/server/page');21const { ElementHandle } = require('playwright/lib/server/dom');22const { getInternalInstanceChildren } = require('playwright/lib/server/dom');23const { Page } = require('playwright/lib/server/page');24const { ElementHandle } = require('playwright/lib/server/dom');25const { getInternalInstanceChildren } = require('playwright/lib/server/dom');26const { Page } = require('playwright/lib/server/page');27const { ElementHandle
Using AI Code Generation
1const playwright = require("playwright");2const { InternalInstance } = require("playwright/lib/server/inspector/inspector");3const { chromium } = require("playwright");4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();8 const internalInstance = new InternalInstance(page);9 const children = await internalInstance.getInternalInstanceChildren();10 console.log(children);11 await browser.close();12})();13 {14 _creationFrame: {15 },16 {17 }18 }19const playwright = require("playwright");20const { InternalInstance } = require("playwright/lib/server/inspector/inspector");21const { chr
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.
Get 100 minutes of automation test minutes FREE!!