Best JavaScript code snippet using wpt
webusb-test.js
Source:webusb-test.js
1'use strict';2// This polyfill library implements the WebUSB Test API as specified here:3// https://wicg.github.io/webusb/test/4(() => {5// These variables are logically members of the USBTest class but are defined6// here to hide them from being visible as fields of navigator.usb.test.7let internal = {8 intialized: false,9 webUsbService: null,10 webUsbServiceInterceptor: null,11 messagePort: null,12};13let mojom = {};14async function loadMojomDefinitions() {15 const deviceMojom =16 await import('/gen/services/device/public/mojom/usb_device.mojom.m.js');17 const serviceMojom = await import(18 '/gen/third_party/blink/public/mojom/usb/web_usb_service.mojom.m.js');19 return {20 ...deviceMojom,21 ...serviceMojom,22 };23}24function getMessagePort(target) {25 return new Promise(resolve => {26 target.addEventListener('message', messageEvent => {27 if (messageEvent.data.type === 'ReadyForAttachment') {28 if (internal.messagePort === null) {29 internal.messagePort = messageEvent.data.port;30 }31 resolve();32 }33 }, {once: true});34 });35}36// Converts an ECMAScript String object to an instance of37// mojo_base.mojom.String16.38function mojoString16ToString(string16) {39 return String.fromCharCode.apply(null, string16.data);40}41// Converts an instance of mojo_base.mojom.String16 to an ECMAScript String.42function stringToMojoString16(string) {43 let array = new Array(string.length);44 for (var i = 0; i < string.length; ++i) {45 array[i] = string.charCodeAt(i);46 }47 return { data: array }48}49function fakeDeviceInitToDeviceInfo(guid, init) {50 let deviceInfo = {51 guid: guid + "",52 usbVersionMajor: init.usbVersionMajor,53 usbVersionMinor: init.usbVersionMinor,54 usbVersionSubminor: init.usbVersionSubminor,55 classCode: init.deviceClass,56 subclassCode: init.deviceSubclass,57 protocolCode: init.deviceProtocol,58 vendorId: init.vendorId,59 productId: init.productId,60 deviceVersionMajor: init.deviceVersionMajor,61 deviceVersionMinor: init.deviceVersionMinor,62 deviceVersionSubminor: init.deviceVersionSubminor,63 manufacturerName: stringToMojoString16(init.manufacturerName),64 productName: stringToMojoString16(init.productName),65 serialNumber: stringToMojoString16(init.serialNumber),66 activeConfiguration: init.activeConfigurationValue,67 configurations: []68 };69 init.configurations.forEach(config => {70 var configInfo = {71 configurationValue: config.configurationValue,72 configurationName: stringToMojoString16(config.configurationName),73 selfPowered: false,74 remoteWakeup: false,75 maximumPower: 0,76 interfaces: [],77 extraData: new Uint8Array()78 };79 config.interfaces.forEach(iface => {80 var interfaceInfo = {81 interfaceNumber: iface.interfaceNumber,82 alternates: []83 };84 iface.alternates.forEach(alternate => {85 var alternateInfo = {86 alternateSetting: alternate.alternateSetting,87 classCode: alternate.interfaceClass,88 subclassCode: alternate.interfaceSubclass,89 protocolCode: alternate.interfaceProtocol,90 interfaceName: stringToMojoString16(alternate.interfaceName),91 endpoints: [],92 extraData: new Uint8Array()93 };94 alternate.endpoints.forEach(endpoint => {95 var endpointInfo = {96 endpointNumber: endpoint.endpointNumber,97 packetSize: endpoint.packetSize,98 synchronizationType: mojom.UsbSynchronizationType.NONE,99 usageType: mojom.UsbUsageType.DATA,100 pollingInterval: 0,101 extraData: new Uint8Array()102 };103 switch (endpoint.direction) {104 case "in":105 endpointInfo.direction = mojom.UsbTransferDirection.INBOUND;106 break;107 case "out":108 endpointInfo.direction = mojom.UsbTransferDirection.OUTBOUND;109 break;110 }111 switch (endpoint.type) {112 case "bulk":113 endpointInfo.type = mojom.UsbTransferType.BULK;114 break;115 case "interrupt":116 endpointInfo.type = mojom.UsbTransferType.INTERRUPT;117 break;118 case "isochronous":119 endpointInfo.type = mojom.UsbTransferType.ISOCHRONOUS;120 break;121 }122 alternateInfo.endpoints.push(endpointInfo);123 });124 interfaceInfo.alternates.push(alternateInfo);125 });126 configInfo.interfaces.push(interfaceInfo);127 });128 deviceInfo.configurations.push(configInfo);129 });130 return deviceInfo;131}132function convertMojoDeviceFilters(input) {133 let output = [];134 input.forEach(filter => {135 output.push(convertMojoDeviceFilter(filter));136 });137 return output;138}139function convertMojoDeviceFilter(input) {140 let output = {};141 if (input.hasVendorId)142 output.vendorId = input.vendorId;143 if (input.hasProductId)144 output.productId = input.productId;145 if (input.hasClassCode)146 output.classCode = input.classCode;147 if (input.hasSubclassCode)148 output.subclassCode = input.subclassCode;149 if (input.hasProtocolCode)150 output.protocolCode = input.protocolCode;151 if (input.serialNumber)152 output.serialNumber = mojoString16ToString(input.serialNumber);153 return output;154}155class FakeDevice {156 constructor(deviceInit) {157 this.info_ = deviceInit;158 this.opened_ = false;159 this.currentConfiguration_ = null;160 this.claimedInterfaces_ = new Map();161 }162 getConfiguration() {163 if (this.currentConfiguration_) {164 return Promise.resolve({165 value: this.currentConfiguration_.configurationValue });166 } else {167 return Promise.resolve({ value: 0 });168 }169 }170 open() {171 assert_false(this.opened_);172 this.opened_ = true;173 return Promise.resolve({error: mojom.UsbOpenDeviceError.OK});174 }175 close() {176 assert_true(this.opened_);177 this.opened_ = false;178 return Promise.resolve();179 }180 setConfiguration(value) {181 assert_true(this.opened_);182 let selectedConfiguration = this.info_.configurations.find(183 configuration => configuration.configurationValue == value);184 // Blink should never request an invalid configuration.185 assert_not_equals(selectedConfiguration, undefined);186 this.currentConfiguration_ = selectedConfiguration;187 return Promise.resolve({ success: true });188 }189 async claimInterface(interfaceNumber) {190 assert_true(this.opened_);191 assert_false(this.currentConfiguration_ == null, 'device configured');192 assert_false(this.claimedInterfaces_.has(interfaceNumber),193 'interface already claimed');194 const protectedInterfaces = new Set([195 mojom.USB_AUDIO_CLASS,196 mojom.USB_HID_CLASS,197 mojom.USB_MASS_STORAGE_CLASS,198 mojom.USB_SMART_CARD_CLASS,199 mojom.USB_VIDEO_CLASS,200 mojom.USB_AUDIO_VIDEO_CLASS,201 mojom.USB_WIRELESS_CLASS,202 ]);203 let iface = this.currentConfiguration_.interfaces.find(204 iface => iface.interfaceNumber == interfaceNumber);205 // Blink should never request an invalid interface or alternate.206 assert_false(iface == undefined);207 if (iface.alternates.some(208 alt => protectedInterfaces.has(alt.interfaceClass))) {209 return {result: mojom.UsbClaimInterfaceResult.kProtectedClass};210 }211 this.claimedInterfaces_.set(interfaceNumber, 0);212 return {result: mojom.UsbClaimInterfaceResult.kSuccess};213 }214 releaseInterface(interfaceNumber) {215 assert_true(this.opened_);216 assert_false(this.currentConfiguration_ == null, 'device configured');217 assert_true(this.claimedInterfaces_.has(interfaceNumber));218 this.claimedInterfaces_.delete(interfaceNumber);219 return Promise.resolve({ success: true });220 }221 setInterfaceAlternateSetting(interfaceNumber, alternateSetting) {222 assert_true(this.opened_);223 assert_false(this.currentConfiguration_ == null, 'device configured');224 assert_true(this.claimedInterfaces_.has(interfaceNumber));225 let iface = this.currentConfiguration_.interfaces.find(226 iface => iface.interfaceNumber == interfaceNumber);227 // Blink should never request an invalid interface or alternate.228 assert_false(iface == undefined);229 assert_true(iface.alternates.some(230 x => x.alternateSetting == alternateSetting));231 this.claimedInterfaces_.set(interfaceNumber, alternateSetting);232 return Promise.resolve({ success: true });233 }234 reset() {235 assert_true(this.opened_);236 return Promise.resolve({ success: true });237 }238 clearHalt(endpoint) {239 assert_true(this.opened_);240 assert_false(this.currentConfiguration_ == null, 'device configured');241 // TODO(reillyg): Assert that endpoint is valid.242 return Promise.resolve({ success: true });243 }244 async controlTransferIn(params, length, timeout) {245 assert_true(this.opened_);246 if ((params.recipient == mojom.UsbControlTransferRecipient.INTERFACE ||247 params.recipient == mojom.UsbControlTransferRecipient.ENDPOINT) &&248 this.currentConfiguration_ == null) {249 return {250 status: mojom.UsbTransferStatus.PERMISSION_DENIED,251 };252 }253 return {254 status: mojom.UsbTransferStatus.OK,255 data: [256 length >> 8, length & 0xff, params.request, params.value >> 8,257 params.value & 0xff, params.index >> 8, params.index & 0xff258 ]259 };260 }261 async controlTransferOut(params, data, timeout) {262 assert_true(this.opened_);263 if ((params.recipient == mojom.UsbControlTransferRecipient.INTERFACE ||264 params.recipient == mojom.UsbControlTransferRecipient.ENDPOINT) &&265 this.currentConfiguration_ == null) {266 return {267 status: mojom.UsbTransferStatus.PERMISSION_DENIED,268 };269 }270 return {status: mojom.UsbTransferStatus.OK, bytesWritten: data.byteLength};271 }272 genericTransferIn(endpointNumber, length, timeout) {273 assert_true(this.opened_);274 assert_false(this.currentConfiguration_ == null, 'device configured');275 // TODO(reillyg): Assert that endpoint is valid.276 let data = new Array(length);277 for (let i = 0; i < length; ++i)278 data[i] = i & 0xff;279 return Promise.resolve({status: mojom.UsbTransferStatus.OK, data: data});280 }281 genericTransferOut(endpointNumber, data, timeout) {282 assert_true(this.opened_);283 assert_false(this.currentConfiguration_ == null, 'device configured');284 // TODO(reillyg): Assert that endpoint is valid.285 return Promise.resolve(286 {status: mojom.UsbTransferStatus.OK, bytesWritten: data.byteLength});287 }288 isochronousTransferIn(endpointNumber, packetLengths, timeout) {289 assert_true(this.opened_);290 assert_false(this.currentConfiguration_ == null, 'device configured');291 // TODO(reillyg): Assert that endpoint is valid.292 let data = new Array(packetLengths.reduce((a, b) => a + b, 0));293 let dataOffset = 0;294 let packets = new Array(packetLengths.length);295 for (let i = 0; i < packetLengths.length; ++i) {296 for (let j = 0; j < packetLengths[i]; ++j)297 data[dataOffset++] = j & 0xff;298 packets[i] = {299 length: packetLengths[i],300 transferredLength: packetLengths[i],301 status: mojom.UsbTransferStatus.OK302 };303 }304 return Promise.resolve({ data: data, packets: packets });305 }306 isochronousTransferOut(endpointNumber, data, packetLengths, timeout) {307 assert_true(this.opened_);308 assert_false(this.currentConfiguration_ == null, 'device configured');309 // TODO(reillyg): Assert that endpoint is valid.310 let packets = new Array(packetLengths.length);311 for (let i = 0; i < packetLengths.length; ++i) {312 packets[i] = {313 length: packetLengths[i],314 transferredLength: packetLengths[i],315 status: mojom.UsbTransferStatus.OK316 };317 }318 return Promise.resolve({ packets: packets });319 }320}321class FakeWebUsbService {322 constructor() {323 this.receiver_ = new mojom.WebUsbServiceReceiver(this);324 this.devices_ = new Map();325 this.devicesByGuid_ = new Map();326 this.client_ = null;327 this.nextGuid_ = 0;328 }329 addBinding(handle) {330 this.receiver_.$.bindHandle(handle);331 }332 addDevice(fakeDevice, info) {333 let device = {334 fakeDevice: fakeDevice,335 guid: (this.nextGuid_++).toString(),336 info: info,337 receivers: [],338 };339 this.devices_.set(fakeDevice, device);340 this.devicesByGuid_.set(device.guid, device);341 if (this.client_)342 this.client_.onDeviceAdded(fakeDeviceInitToDeviceInfo(device.guid, info));343 }344 removeDevice(fakeDevice) {345 let device = this.devices_.get(fakeDevice);346 if (!device)347 throw new Error('Cannot remove unknown device.');348 for (const receiver of device.receivers)349 receiver.$.close();350 this.devices_.delete(device.fakeDevice);351 this.devicesByGuid_.delete(device.guid);352 if (this.client_) {353 this.client_.onDeviceRemoved(354 fakeDeviceInitToDeviceInfo(device.guid, device.info));355 }356 }357 removeAllDevices() {358 this.devices_.forEach(device => {359 for (const receiver of device.receivers)360 receiver.$.close();361 this.client_.onDeviceRemoved(362 fakeDeviceInitToDeviceInfo(device.guid, device.info));363 });364 this.devices_.clear();365 this.devicesByGuid_.clear();366 }367 getDevices() {368 let devices = [];369 this.devices_.forEach(device => {370 devices.push(fakeDeviceInitToDeviceInfo(device.guid, device.info));371 });372 return Promise.resolve({ results: devices });373 }374 getDevice(guid, request) {375 let retrievedDevice = this.devicesByGuid_.get(guid);376 if (retrievedDevice) {377 const receiver =378 new mojom.UsbDeviceReceiver(new FakeDevice(retrievedDevice.info));379 receiver.$.bindHandle(request.handle);380 receiver.onConnectionError.addListener(() => {381 if (retrievedDevice.fakeDevice.onclose)382 retrievedDevice.fakeDevice.onclose();383 });384 retrievedDevice.receivers.push(receiver);385 } else {386 request.handle.close();387 }388 }389 getPermission(deviceFilters) {390 return new Promise(resolve => {391 if (navigator.usb.test.onrequestdevice) {392 navigator.usb.test.onrequestdevice(393 new USBDeviceRequestEvent(deviceFilters, resolve));394 } else {395 resolve({ result: null });396 }397 });398 }399 setClient(client) {400 this.client_ = client;401 }402}403class USBDeviceRequestEvent {404 constructor(deviceFilters, resolve) {405 this.filters = convertMojoDeviceFilters(deviceFilters);406 this.resolveFunc_ = resolve;407 }408 respondWith(value) {409 // Wait until |value| resolves (if it is a Promise). This function returns410 // no value.411 Promise.resolve(value).then(fakeDevice => {412 let device = internal.webUsbService.devices_.get(fakeDevice);413 let result = null;414 if (device) {415 result = fakeDeviceInitToDeviceInfo(device.guid, device.info);416 }417 this.resolveFunc_({ result: result });418 }, () => {419 this.resolveFunc_({ result: null });420 });421 }422}423// Unlike FakeDevice this class is exported to callers of USBTest.addFakeDevice.424class FakeUSBDevice {425 constructor() {426 this.onclose = null;427 }428 disconnect() {429 setTimeout(() => internal.webUsbService.removeDevice(this), 0);430 }431}432class USBTest {433 constructor() {434 this.onrequestdevice = undefined;435 }436 async initialize() {437 if (internal.initialized)438 return;439 // Be ready to handle 'ReadyForAttachment' message from child iframes.440 if ('window' in self) {441 getMessagePort(window);442 }443 mojom = await loadMojomDefinitions();444 internal.webUsbService = new FakeWebUsbService();445 internal.webUsbServiceInterceptor =446 new MojoInterfaceInterceptor(mojom.WebUsbService.$interfaceName);447 internal.webUsbServiceInterceptor.oninterfacerequest =448 e => internal.webUsbService.addBinding(e.handle);449 internal.webUsbServiceInterceptor.start();450 // Wait for a call to GetDevices() to pass between the renderer and the451 // mock in order to establish that everything is set up.452 await navigator.usb.getDevices();453 internal.initialized = true;454 }455 // Returns a promise that is resolved when the implementation of |usb| in the456 // global scope for |context| is controlled by the current context.457 attachToContext(context) {458 if (!internal.initialized)459 throw new Error('Call initialize() before attachToContext()');460 let target = context.constructor.name === 'Worker' ? context : window;461 return getMessagePort(target).then(() => {462 return new Promise(resolve => {463 internal.messagePort.onmessage = channelEvent => {464 switch (channelEvent.data.type) {465 case mojom.WebUsbService.$interfaceName:466 internal.webUsbService.addBinding(channelEvent.data.handle);467 break;468 case 'Complete':469 resolve();470 break;471 }472 };473 internal.messagePort.postMessage({474 type: 'Attach',475 interfaces: [476 mojom.WebUsbService.$interfaceName,477 ]478 });479 });480 });481 }482 addFakeDevice(deviceInit) {483 if (!internal.initialized)484 throw new Error('Call initialize() before addFakeDevice().');485 // |addDevice| and |removeDevice| are called in a setTimeout callback so486 // that tests do not rely on the device being immediately available which487 // may not be true for all implementations of this test API.488 let fakeDevice = new FakeUSBDevice();489 setTimeout(490 () => internal.webUsbService.addDevice(fakeDevice, deviceInit), 0);491 return fakeDevice;492 }493 reset() {494 if (!internal.initialized)495 throw new Error('Call initialize() before reset().');496 // Reset the mocks in a setTimeout callback so that tests do not rely on497 // the fact that this polyfill can do this synchronously.498 return new Promise(resolve => {499 setTimeout(() => {500 if (internal.messagePort !== null)501 internal.messagePort.close();502 internal.messagePort = null;503 internal.webUsbService.removeAllDevices();504 resolve();505 }, 0);506 });507 }508}509navigator.usb.test = new USBTest();...
Using AI Code Generation
1var wptoolkit = require('wptoolkit');2wptoolkit.protectedInterfaces(function(err, data){3 if(err){4 console.log(err);5 }else{6 console.log(data);7 }8});9var wptoolkit = require('wptoolkit');10wptoolkit.getInterface('wlan0', function(err, data){11 if(err){12 console.log(err);13 }else{14 console.log(data);15 }16});17var wptoolkit = require('wptoolkit');18wptoolkit.getInterfaces(function(err, data){19 if(err){20 console.log(err);21 }else{22 console.log(data);23 }24});25var wptoolkit = require('wptoolkit');26wptoolkit.getInterface('wlan0', function(err, data){27 if(err){28 console.log(err);29 }else{30 console.log(data);31 }32});33var wptoolkit = require('wptoolkit');34wptoolkit.getInterfaces(function(err, data){35 if(err){36 console.log(err);37 }else{38 console.log(data);39 }40});41var wptoolkit = require('wptoolkit');42wptoolkit.getInterface('wlan0', function(err, data){43 if(err){44 console.log(err);45 }else{46 console.log(data);47 }48});49var wptoolkit = require('wptoolkit');50wptoolkit.getInterfaces(function(err, data){51 if(err){52 console.log(err);53 }else{54 console.log(data);55 }56});57var wptoolkit = require('wptoolkit');58wptoolkit.getInterface('wlan0', function(err, data){59 if(err){60 console.log(err);61 }else{62 console.log(data);
Using AI Code Generation
1var wptoolkit = require('wptoolkit');2var protectedInterfaces = wptoolkit.protectedInterfaces;3var interfaces = protectedInterfaces();4console.log(interfaces);5var wptoolkit = require('wptoolkit');6var protectedInterfaces = wptoolkit.protectedInterfaces;7var interfaces = protectedInterfaces();8console.log(interfaces);9This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
Using AI Code Generation
1var wptoolkit = require('wptoolkit');2wptoolkit.protectedInterfaces(function (err, data) {3 console.log(data);4});5var wptoolkit = require('wptoolkit');6wptoolkit.protectedInterfaces(function (err, data) {7 console.log(data);8});9var wptoolkit = require('wptoolkit');10wptoolkit.protectedInterfaces(function (err, data) {11 console.log(data);12});13var wptoolkit = require('wptoolkit');14wptoolkit.protectedInterfaces(function (err, data) {15 console.log(data);16});17var wptoolkit = require('wptoolkit');18wptoolkit.protectedInterfaces(function (err, data) {19 console.log(data);20});21var wptoolkit = require('wptoolkit');22wptoolkit.protectedInterfaces(function (err, data) {23 console.log(data);24});25var wptoolkit = require('wptoolkit');26wptoolkit.protectedInterfaces(function (err, data) {27 console.log(data);28});29var wptoolkit = require('wptoolkit');30wptoolkit.protectedInterfaces(function (err, data) {31 console.log(data);32});33var wptoolkit = require('wptoolkit');34wptoolkit.protectedInterfaces(function (err, data) {35 console.log(data);36});37var wptoolkit = require('wptoolkit');38wptoolkit.protectedInterfaces(function (err, data) {
Using AI Code Generation
1var wptoolkit = require('wptoolkit');2var protectedInterfaces = wptoolkit.protectedInterfaces;3protectedInterfaces(function (err, interfaces) {4 if (err) {5 console.log(err);6 }7 else {8 console.log(interfaces);9 }10});11[ { name: 'Local Area Connection',
Using AI Code Generation
1var wptoolkit = require('wptoolkit');2function testProtectedInterfaces() {3 wptoolkit.protectedInterfaces(function(error, result) {4 if (error) {5 console.log("Error: " + error);6 } else {7 console.log("Result: " + result);8 }9 });10}11testProtectedInterfaces();12var wptoolkit = require('wptoolkit');13function testGetNetworkInterfaces() {14 wptoolkit.getNetworkInterfaces(function(error, result) {15 if (error) {16 console.log("Error: " + error);17 } else {18 console.log("Result: " + result);19 }20 });21}22testGetNetworkInterfaces();23var wptoolkit = require('wptoolkit');24function testGetWiredInterfaces() {25 wptoolkit.getWiredInterfaces(function(error, result) {26 if (error) {27 console.log("Error: " + error);28 } else {29 console.log("Result: " + result);30 }31 });32}33testGetWiredInterfaces();34var wptoolkit = require('wptoolkit');35function testGetWirelessInterfaces() {36 wptoolkit.getWirelessInterfaces(function(error, result) {37 if (error) {38 console.log("Error: " + error);39 } else {40 console.log("Result: " + result);41 }42 });43}44testGetWirelessInterfaces();45var wptoolkit = require('wptoolkit');46function testGetInterfaceDetails() {47 wptoolkit.getInterfaceDetails("
Using AI Code Generation
1var wptoolkit = require('wptoolkit');2var protectedInterfaces = wptoolkit.protectedInterfaces;3var wptoolkit = new wptoolkit();4protectedInterfaces.getProtectedInterfaces(function(err, protectedInterfaces){5 if(err){6 console.log(err);7 return;8 }9 console.log(protectedInterfaces);10});11var wptoolkit = require('wptoolkit');12var protectedInterfaces = wptoolkit.protectedInterfaces;13var wptoolkit = new wptoolkit();14protectedInterfaces.getProtectedInterfaces(function(err, protectedInterfaces){15 if(err){16 console.log(err);17 return;18 }19 console.log(protectedInterfaces);20});21var wptoolkit = require('wptoolkit');22var protectedInterfaces = wptoolkit.protectedInterfaces;23var wptoolkit = new wptoolkit();24protectedInterfaces.getProtectedInterfaces(function(err, protectedInterfaces){25 if(err){26 console.log(err);27 return;28 }29 console.log(protectedInterfaces);30});31var wptoolkit = require('wptoolkit');32var protectedInterfaces = wptoolkit.protectedInterfaces;33var wptoolkit = new wptoolkit();34protectedInterfaces.getProtectedInterfaces(function(err, protectedInterfaces){35 if(err){36 console.log(err);37 return;38 }39 console.log(protectedInterfaces);40});41var wptoolkit = require('wptoolkit');42var protectedInterfaces = wptoolkit.protectedInterfaces;43var wptoolkit = new wptoolkit();44protectedInterfaces.getProtectedInterfaces(function(err, protectedInterfaces){45 if(err){46 console.log(err);47 return;48 }49 console.log(protectedInterfaces);50});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!