How to use pushHostRootContext method in Playwright Internal

Best JavaScript code snippet using playwright-internal

fiberBeginWork.js

Source:fiberBeginWork.js Github

copy

Full Screen

...17import { ConcurrentMode } from '../shared/ReactTypeOfMode';18import { shouldSetTextContent } from './ReactDOMHostConfig';19import { pushHostContainer } from './fiberHostContext';20let didReceiveUpdate = false;21// function pushHostRootContext(workInProgress) {22// const root = workInProgress.stateNode23// if (root.pendingContext) {24// pushTopLevelContextObject(25// workInProgress,26// root.pendingContext,27// root.pendingContext !== root.context28// )29// } else if (root.context) {30// pushTopLevelContextObject(workInProgress, root.context, false);31// }32// pushHostContainer(workInProgress, root.containerInfo)33// }34function markRef(current, workInProgress) {35 const ref = workInProgress.ref;36 if (37 (current === null && ref !== null) ||38 (current !== null && current.ref !== ref)39 ) {40 // Schedule a Ref effect41 workInProgress.effectTag |= Ref;42 }43}44function updateHostComponent(current, workInProgress, renderExpirationTime) {45 // context46 const type = workInProgress.type;47 const nextProps = workInProgress.pendingProps;48 const prevProps = current !== null ? current.memoizedProps : null;49 let nextChildren = nextProps.children;50 const isDirectTextChild = shouldSetTextContent(type, nextProps);51 if (isDirectTextChild) {52 nextChildren = null;53 } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {54 workInProgress.effectTag |= ContentReset;55 }56 if (57 workInProgress.mode & ConcurrentMode &&58 renderExpirationTime !== Never59 ) {60 // TODO61 }62 markRef(current, workInProgress);63 reconcileChildren(64 current,65 workInProgress,66 nextChildren,67 renderExpirationTime,68 );69 return workInProgress.child;70}71export function mountIndeterminateComponent(72 _current,73 workInProgress,74 Component,75 renderExpirationTime,76) {77 if (_current !== null) {78 // TODO79 }80 const props = workInProgress.pendingProps;81 // TODO context82 let context;83 let value;84 value = renderWithHooks(85 null,86 workInProgress,87 Component,88 props,89 context,90 renderExpirationTime,91 );92 workInProgress.effectTag |= PerformedWork;93 if (94 typeof value === 'object' &&95 value !== null &&96 typeof value.render === 'function' &&97 value.$$typeof === undefined98 ) {99 // TODO100 } else {101 workInProgress.tag = FunctionComponent;102 reconcileChildren(null, workInProgress, value, renderExpirationTime);103 }104 return workInProgress.child;105}106export function reconcileChildren(107 current,108 workInProgress,109 nextChildren,110 renderExpirationTime,111) {112 if (current === null) {113 // TODO114 // 创建fiber115 workInProgress.child = mountChildFibers(116 workInProgress,117 null,118 nextChildren,119 renderExpirationTime,120 );121 } else {122 workInProgress.child = reconcileChildFibers(123 workInProgress,124 current.child,125 nextChildren,126 renderExpirationTime,127 );128 }129}130function pushHostRootContext(workInProgress) {131 const root = workInProgress.stateNode;132 if (root.pendingContext) {133 // TODO134 } else if (root.context) {135 // TODO136 }137 pushHostContainer(workInProgress, root.containerInfo);138}139function updateHostRoot(current, workInProgress, renderExpirationTime) {140 // TODO 将root的上下文推入141 pushHostRootContext(workInProgress);142 const updateQueue = workInProgress.updateQueue;143 const nextProps = workInProgress.pendingProps;144 const prevState = workInProgress.memoizedState;145 const pervChildren = prevState !== null ? prevState.element : null;146 processUpdateQueue(147 workInProgress,148 updateQueue,149 nextProps,150 null,151 renderExpirationTime,152 );153 const nextState = workInProgress.memoizedState;154 const nextChildren = nextState.element;155 if (nextChildren === pervChildren) {...

Full Screen

Full Screen

ReactFiberBeginWork.js

Source:ReactFiberBeginWork.js Github

copy

Full Screen

...34 renderLanes35 );36 }37}38function pushHostRootContext(workInProgress) {39 const root = workInProgress.stateNode;40 if(root.pendingContext) {41 pushTopLevelContextObject(42 workInProgress,43 root.pendingContext,44 root.pendingContext !== root.context45 )46 } else {47 pushTopLevelContextObject(workInProgress, root.context, false);48 }49 pushHostContainer(workInProgress, root.containerInfo);50}51function updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes) {52 let context;53 prepareToReadContext(workInProgress, renderLanes);54 let nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, '', renderLanes);55 if(current !== null && !didReceiveUpdate) {56 bailoutHooks(current, workInProgress, renderLanes);57 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);58 }59 reconcileChildren(current, workInProgress, nextChildren, renderLanes);60 return workInProgress.child;61}62function updateHostRoot(current, workInProgress, renderLanes) {63 pushHostRootContext(workInProgress);64 const updateQueue = workInProgress.updateQueue;65 const nexrProps = workInProgress.pendingProps;66 const prevState = workInProgress.memoizedState;67 const prevChildren = prevState !== null ? prevState.element: null;68 cloneUpdateQueue(current, workInProgress);69 // 处理更新队列事物70 processUpdateQueue(workInProgress, nexrProps, null, renderLanes);71 const nextState = workInProgress.memoizedState;72 const nextChildren = nextState.element;73 if(nextChildren === prevChildren) {74 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);75 }76 reconcileChildren(current, workInProgress, nextChildren, renderLanes);77 return workInProgress.child;78}79function updateHostComponent(current, workInProgress, renderLanes) {80 pushHostContext(workInProgress);81 const type = workInProgress.type;82 const nextProps = workInProgress.pendingProps;83 const prevProps = current !== null ? current.memoizedProps : null;84 let nextChildren = nextProps.children;85 const isDirectTextChild = shouldSetTextContent(type, nextProps);86 if(isDirectTextChild) {87 nextChildren = null;88 } else if(prevProps !== null && shouldSetTextContent(type, prevProps)) {89 workInProgress.flags |= ContentReset;90 }91 workInProgress.flags |= PerformedWork;92 reconcileChildren(current, workInProgress, nextChildren, renderLanes);93 return workInProgress.child;94}95function updateHostText(current, workInProgress) {96 return null;97}98function mountIndeterminateComponent(_current, workInProgress, Component, renderLanes) {99 if(_current !== null) {100 _current.alternate = null;101 workInProgress.alternate = null;102 workInProgress.flags |= Placement;103 } 104 const props = workInProgress.pendingProps;105 let context;106 prepareToReadContext(workInProgress, renderLanes);107 let value;108 value = renderWithHooks(109 null,110 workInProgress,111 Component,112 props,113 context,114 renderLanes115 );116 workInProgress.flags |= PerformedWork;117 if(118 !disableModulePatternComponents &&119 typeof value === 'object' &&120 value !== null &&121 typeof value.render === 'function' &&122 value.$$typeof === undefined123 ) {124 } else {125 workInProgress.tag = FunctionComponent;126 reconcileChildren(null, workInProgress, value, renderLanes);127 return workInProgress.child;128 }129}130function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) {131 if(current !== null) {132 workInProgress.dependencies = current.dependencies;133 }134 markSkippedUpdateLanes(workInProgress.lanes);135 if(!includesSomeLane(renderLanes, workInProgress.childLanes)) {136 return null;137 } else {138 cloneChildFibers(current, workInProgress);139 return workInProgress.child;140 }141}142function beginWork(current, workInProgress, renderLanes) {143 const updateLanes = workInProgress.lanes;144 // 更新过程中,current不为null145 if(current !== null) {146 const oldProps = current.memoizedProps;147 const newProps = workInProgress.pendingProps;148 // 比较新旧props149 if(oldProps !== newProps) {150 // 当前fiber需要更新151 didReceiveUpdate = true;152 } else if(!includesSomeLane(renderLanes, updateLanes)) {153 didReceiveUpdate = false;154 switch(workInProgress.tag) {155 case HostRoot: {156 pushHostRootContext(workInProgress);157 break;158 }159 case HostComponent:160 pushHostContext(workInProgress);161 break;162 }163 // 判断子fiber是否需要更新164 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);165 } else {166 if((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {167 didReceiveUpdate = true;168 } else {169 didReceiveUpdate = false;170 }...

Full Screen

Full Screen

updateHostRoot.js

Source:updateHostRoot.js Github

copy

Full Screen

1function updateHostRoot(current, workInProgress, renderExpirationTime) {2 // 将当前workInProgress的相关属性(dom,fiber,context)存储到reactFilberStack中3 pushHostRootContext(workInProgress);45 var updateQueue = workInProgress.updateQueue;6 if (updateQueue !== null) {7 var prevState = workInProgress.memoizedState;8 // 解析优先级足够的更新,获取最新的state,见 ../updateQueue.js9 var state = processUpdateQueue(current, workInProgress, updateQueue, null, null, renderExpirationTime);1011 // 设置为 workInProgress.memoizeState = state12 memoizeState(workInProgress, state);13 updateQueue = workInProgress.updateQueue;1415 var element = void 0;1617 // workInProgress.updateQueue不为空 (可能有优先级不够的被跳过) 并且 有捕获到的值(错误)18 if (updateQueue !== null && updateQueue.capturedValues !== null) {19 // There's an uncaught error. Unmount the whole root.20 element = null;21 } else if (prevState === state) {22 // If the state is the same as before, that's a bailout because we had23 // no work that expires at this time.2425 // 跟新的时候如果发现state相同,克隆所有的子节点26 resetHydrationState();27 return bailoutOnAlreadyFinishedWork(current, workInProgress);28 } else {29 // 首次插入的时候30 element = state.element;31 }32 var root = workInProgress.stateNode;3334 // 服务端输出 ???35 if ((current === null || current.child === null) && root.hydrate && enterHydrationState(workInProgress)) {36 // If we don't have any current children this might be the first pass.37 // We always try to hydrate. If this isn't a hydration pass there won't38 // be any children to hydrate which is effectively the same thing as39 // not hydrating.4041 // This is a bit of a hack. We track the host root as a placement to42 // know that we're currently in a mounting state. That way isMounted43 // works as expected. We must reset this before committing.44 // TODO: Delete this when we delete isMounted and findDOMNode.45 workInProgress.effectTag |= Placement;4647 // Ensure that children mount into this root without tracking48 // side-effects. This ensures that we don't store Placement effects on49 // nodes that will be hydrated.50 workInProgress.child = mountChildFibers(workInProgress, null, element, renderExpirationTime);51 } else {52 // Otherwise reset hydration state in case we aborted and resumed another53 // root.5455 // 重置各种跟 hydrate 相关的变量,忽略,暂时没什么卵用56 resetHydrationState();5758 // 花式插入各种child59 reconcileChildren(current, workInProgress, element);60 }61 memoizeState(workInProgress, state);62 return workInProgress.child;63 }64 resetHydrationState();656667 // If there is no update queue, that's a bailout because the root has no props.68 // 如果当前 workInProgress 没有更新队列69 return bailoutOnAlreadyFinishedWork(current, workInProgress);70}7172var NO_CONTEXT = {};73var contextStackCursor = createCursor(NO_CONTEXT);74var contextFiberStackCursor = createCursor(NO_CONTEXT);75var rootInstanceStackCursor = createCursor(NO_CONTEXT);767778function pushHostRootContext(workInProgress) {7980 // context相关 暂时忽略81 var root = workInProgress.stateNode; // fiberRoot实例82 if (root.pendingContext) {83 pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context);84 } else if (root.context) {85 // Should always be set86 pushTopLevelContextObject(workInProgress, root.context, false);87 }88 pushHostContainer(workInProgress, root.containerInfo);89}909192// 将当前的 container (根组件所在DOM) 添加到stack中 ...

Full Screen

Full Screen

begin-work.js

Source:begin-work.js Github

copy

Full Screen

...22 typeof props.dangerouslySetInnerHTML === 'object'23 && props.dangerouslySetInnerHTML !== null24 && typeof props.dangerouslySetInnerHTML.__html === 'string';25}26function pushHostRootContext(WIP: FNode): void {27 const root = WIP.instanceNode;28 pushHostContainer(WIP, root.containerInfo);29}30function updateRoot(current: FNode | null, WIP: FNode): FNode | null {31 pushHostRootContext(WIP);32 const rootRender = WIP.rootRender;33 const nextProps = WIP.props;34 const prevState = WIP.prevState;35 const prevChild = prevState !== null36 ? prevState.element37 : null;38 // processUpdateQueue(WIP, updateQueue, nextProps, null);39 updateRootRender(WIP, rootRender, nextProps, null)40 const nextState = WIP.prevState;41 const nextChildren = nextState.element;42 reconcileChildren(current, WIP, nextChildren);43 return WIP.child;44}45function updateDomNode(current: FNode | null, WIP: FNode): FNode | null {46 const type = WIP.type;47 const nextProps = WIP.props;48 const prevProps = current !== null49 ? current.prevProps50 : null;51 let nextChildren = nextProps.children;52 reconcileChildren(current, WIP, nextChildren);53 saveProps(WIP, nextProps);54 return WIP.child;55}56function updateFunctionComponent(current: FNode | null, WIP: FNode, status): FNode | null {57 const Component = WIP.type;58 const unresolvedProps = WIP.props;59 const nextProps = resolveDefaultProps(Component, unresolvedProps);60 if (current !== null && status === Status.NoWork) {61 const prevProps = current.prevProps;62 if (shallowEqual(prevProps, nextProps) && current.ref === WIP.ref) {63 cloneChildFNodes(current, WIP);64 return WIP.child;65 }66 }67 let nextChildren;68 prepareWithState(current, WIP);69 nextChildren = Component(nextProps);70 nextChildren = finishedWith(Component, nextProps, nextChildren);71 WIP.effectTag |= PerformedWork;72 reconcileChildren(current, WIP, nextChildren);73 return WIP.child;74}75function updateTextNode(current, WIP) {76 const nextProps = WIP.props;77 saveProps(WIP, nextProps);78 return null;79}80function updateFragment(current, WIP) {81 const nextChildren = WIP.props;82 reconcileChildren(current, WIP, nextChildren);83 return WIP.child;84}85function resolveDefaultProps(Component: Function, baseProps: any) {86 if (Component && Component.defaultProps) {87 // Resolve default props. Taken from ReactElement88 const props = Object.assign({}, baseProps);89 const defaultProps = Component.defaultProps;90 for (let propName in defaultProps) {91 if (props[propName] === undefined) {92 props[propName] = defaultProps[propName];93 }94 }95 return props;96 }97 return baseProps;98}99/**100* @param {FNode} current101* @param {FNode} WIP102* @return {FNode | null}103*/104export function beginWork(current: FNode | null, WIP: FNode): FNode | null {105 const status = WIP.status;106 if (current !== null) {107 const oldProps = current.prevProps;108 const newProps = WIP.props;109 if (oldProps === newProps && WIP.status === Status.NoWork) {110 // we just push root to stack111 if (WIP.tag === Root) {112 pushHostRootContext(WIP);113 }114 // clone this fiber and return child115 cloneChildFNodes(current, WIP);116 return WIP.child;117 }118 }119 // reset WIP120 WIP.status = Status.NoWork;121 if (WIP.tag === Root) {122 return updateRoot(current, WIP);123 } else if (WIP.tag === DNode) {124 return updateDomNode(current, WIP);125 } else if (WIP.tag === FComponent) {126 return updateFunctionComponent(current, WIP, status)...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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 await page.screenshot({ path: 'google.png' });7 await browser.close();8})();9const { chromium } = require('playwright');10(async () => {11 const browser = await chromium.launch();12 const context = await browser.newContext();13 const page = await context.newPage();14 await page.evaluate(() => window.__playwright__?.popHostRootContext());15 await page.screenshot({ path: 'google.png' });16 await browser.close();17})();18const { chromium } = require('playwright');19(async () => {20 const browser = await chromium.launch();21 const context = await browser.newContext();22 const page = await context.newPage();23 await page.evaluate(() => window.__playwright__?.resetHostRootContext());24 await page.screenshot({ path: 'google.png' });25 await browser.close();26})();27const { chromium } = require('playwright');28(async () => {29 const browser = await chromium.launch();30 const context = await browser.newContext();31 const page = await context.newPage();32 await page.screenshot({ path: 'google.png' });33 await browser.close();34})();35const { chromium } =

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2const { pushHostRootContext } = require('playwright/lib/server/chromium/crBrowser');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 pushHostRootContext(context, 'example.com', 'example.com');7 const page = await context.newPage();8})();9const { chromium } = require('playwright');10const { pushHostRootContext } = require('playwright/lib/server/chromium/crBrowser');11(async () => {12 const browser = await chromium.launch();13 const context = await browser.newContext();14 pushHostRootContext(context, 'example.com', 'example.com');15 const page = await context.newPage();16})();17const { chromium } = require('playwright');18const { pushHostRootContext } = require('playwright/lib/server/chromium/crBrowser');19(async () => {20 const browser = await chromium.launch();21 const context = await browser.newContext();22 pushHostRootContext(context, 'example.com', 'example.com');23 const page = await context.newPage();24})();25const { chromium } = require('playwright');26const { pushHostRootContext } = require('playwright/lib/server/chromium/crBrowser');27(async () => {28 const browser = await chromium.launch();29 const context = await browser.newContext();30 pushHostRootContext(context, 'example.com', 'example.com');31 const page = await context.newPage();32})();33const { chromium } = require('playwright');34const { pushHostRootContext } = require('playwright/lib/server/chromium/crBrowser');35(async () => {36 const browser = await chromium.launch();37 const context = await browser.newContext();38 pushHostRootContext(context, 'example.com', 'example.com');

Full Screen

Using AI Code Generation

copy

Full Screen

1const { Playwright } = require('@playwright/test');2const playwright = new Playwright();3const browser = await playwright.chromium.launch();4const context = await browser.newContext();5const page = await context.newPage();6const internalContext = page.context();7await internalContext.pushHostRootContext();8console.log('Host Root Context Pushed');9await internalContext.popHostRootContext();10console.log('Host Root Context Popped');11await browser.close();

Full Screen

Using AI Code Generation

copy

Full Screen

1import { chromium } from 'playwright';2(async () => {3 const browser = await chromium.launch({ headless: false });4 const context = await browser.newContext();5 const page = await context.newPage();6 await page.screenshot({ path: `example.png` });7 await browser.close();8})();9Error: Protocol error (Page.navigate): Cannot navigate to invalid URL undefined10Error: Protocol error (Page.navigate): Cannot navigate to invalid URL undefined

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2async function main() {3 const context = await chromium.launchPersistentContext('/tmp/data', {4 });5 const page = await context.newPage();6}7main();8const { chromium } = require('playwright');9async function main() {10 const context = await chromium.launchPersistentContext('/tmp/data', {11 });12 const page = await context.newPage();13}14main();15I have written a test case in playwright to test the functionality of the website. I have used the internal API to use the pushHostRootContext and popHostRootContext methods. I have used the code as follows:But I am getting the following error:TypeError: context.pushHostRootContext is not a functionat Object.main (/Users/abc/playwright/test.js:7:22)at process._tickCallback (internal/process/next_tick.js:68:7)I am not sure what I am doing wrong. Can someone please help me with this?16 at Object.main (/Users/abc/playwright/test.js:7:22)17 at process._tickCallback (internal/process/next_tick.js:68:7)18 at Object.main (/Users/abc/playwright/test.js:7:22)19 at process._tickCallback (internal/process/next_tick.js:68:7)

Full Screen

Using AI Code Generation

copy

Full Screen

1const { _electron } = require('playwright');2const { pushHostRootContext } = _electron;3const { _electron } = require('playwright');4const { pushHostRootContext } = _electron;5const { _electron } = require('playwright');6const { pushHostRootContext } = _electron;7const { _electron } = require('playwright');8const { pushHostRootContext } = _electron;9const { _electron } = require('playwright');10const { pushHostRootContext } = _electron;11const { _electron } = require('playwright');12const { pushHostRootContext } = _electron;13const { _electron } = require('playwright');14const { pushHostRootContext } = _electron;15const { _electron } = require('playwright');16const { pushHostRootContext } = _electron;17const { _electron } = require('playwright');18const { pushHostRootContext } = _electron;19const { _electron } = require('playwright');20const { pushHostRootContext } = _electron;21const { _electron } = require('playwright');22const { pushHostRootContext

Full Screen

Using AI Code Generation

copy

Full Screen

1{2 "scripts": {3 },4 "dependencies": {5 },6 "devDependencies": {7 }8}

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2const { pushHostRootContext } = require('playwright/lib/client/frames');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const context = await pushHostRootContext(browser);6 const page = await context.newPage();7 await page.screenshot({ path: 'google.png' });8 await browser.close();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