How to use serializeType method in Playwright Internal

Best JavaScript code snippet using playwright-internal

Run Playwright Internal automation tests on LambdaTest cloud grid

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

BaseModel.js

Source: BaseModel.js Github

copy
1/**
2 * @author Raj Dye - raj@rajdye.com
3 * Copyright (c) 2014 Institute for Sustainable Performance of Buildings (Superb)
4 */
5goog.provide('lgb.simulation.model.BaseModel');
6
7goog.require('lgb.core.BaseClass');
8
9
10/**
11 * @constructor
12 */
13lgb.simulation.model.BaseModel  = function() {
14
15
16};
17
18
19lgb.simulation.model.BaseModel.prototype.getClassName = function() {
20  
21  var fullClassName = this.getFullClassName();
22  var ary = fullClassName.split('.');
23  
24  var len = ary.length;
25  var className = ary[len-1];
26  
27  return className;
28};
29
30
31lgb.simulation.model.BaseModel.prototype.getClassReference = function() {
32  
33  var fullClassName = this.getFullClassName();
34  var classReference = eval(fullClassName);
35  
36  return classReference;
37};
38
39
40
41
42lgb.simulation.model.BaseModel.prototype.toJSON = function() { 
43    return this.toJSONHelper_();
44};
45
46
47lgb.simulation.model.BaseModel.prototype.toJSONHelper_ = function() { 
48  
49
50  var serializeType = this.serializeType;
51
52  if ( undefined == serializeType) {
53    serializeType = true;
54  }
55
56  var jsonObject = {};
57  
58  if (serializeType) {
59     jsonObject.t = this.getClassName();
60  }
61
62  
63  var classReference = this.getClassReference();
64
65  
66  if (undefined != classReference.fieldPrimitivesEx_) {
67    
68    var fieldPrimitivesEx = classReference.fieldPrimitivesEx_;
69
70    for(var jsFieldName in fieldPrimitivesEx) {
71      var jsonFieldName = fieldPrimitivesEx[jsFieldName];
72      jsonObject[jsonFieldName] = this[jsFieldName];
73    }
74  }
75  
76  if (undefined != classReference.fieldObjectsEx_) {
77    
78    var fieldObjectsEx = classReference.fieldObjectsEx_;
79
80    for(var jsFieldName in fieldObjectsEx) {
81      
82      var fieldObject = fieldObjectsEx[jsFieldName];
83       
84      var jsonFieldName = fieldObject.jsonFieldName;
85      var fieldClassReference = fieldObject.classReference;
86      
87
88      
89      if (this[jsFieldName] != null) {
90        
91      var fieldValue = this[jsFieldName];
92      
93      if (fieldClassReference == lgb.simulation.model.voManaged.SerializableVector) {
94        
95        if (fieldValue instanceof Array) {
96
97          var sv = new lgb.simulation.model.voManaged.SerializableVector(fieldObject.itemTypeString, fieldValue);
98          jsonObject[jsonFieldName] = sv;
99          
100        } else {
101          debugger;
102        }
103
104        
105      } else {
106        jsonObject[jsonFieldName] = fieldValue;
107      }
108
109      }
110
111    }
112  }
113  
114
115  return jsonObject;
116};
117
118
119
120
121
Full Screen

JSBuilder.js

Source: JSBuilder.js Github

copy
1const ts = require('typescript');
2const path = require('path');
3const Documentation = require('./Documentation');
4module.exports = checkSources;
5
6/**
7 * @param {!Array<!import('../Source')>} sources
8 */
9function checkSources(sources) {
10  // special treatment for Events.js
11  const classEvents = new Map();
12  const eventsSource = sources.find(source => source.name() === 'Events.js');
13  if (eventsSource) {
14    const {Events} = require(eventsSource.filePath());
15    for (const [className, events] of Object.entries(Events))
16      classEvents.set(className, Array.from(Object.values(events)).filter(e => typeof e === 'string').map(e => Documentation.Member.createEvent(e)));
17  }
18
19  const excludeClasses = new Set([]);
20  const program = ts.createProgram({
21    options: {
22      allowJs: true,
23      target: ts.ScriptTarget.ES2017
24    },
25    rootNames: sources.map(source => source.filePath())
26  });
27  const checker = program.getTypeChecker();
28  const sourceFiles = program.getSourceFiles();
29  /** @type {!Array<!Documentation.Class>} */
30  const classes = [];
31  /** @type {!Map<string, string>} */
32  const inheritance = new Map();
33  sourceFiles.filter(x => !x.fileName.includes('node_modules')).map(x => visit(x));
34  const errors = [];
35  const documentation = new Documentation(recreateClassesWithInheritance(classes, inheritance));
36
37  return {errors, documentation};
38
39  /**
40   * @param {!Array<!Documentation.Class>} classes
41   * @param {!Map<string, string>} inheritance
42   * @return {!Array<!Documentation.Class>}
43   */
44  function recreateClassesWithInheritance(classes, inheritance) {
45    const classesByName = new Map(classes.map(cls => [cls.name, cls]));
46    return classes.map(cls => {
47      const membersMap = new Map();
48      for (let wp = cls; wp; wp = classesByName.get(inheritance.get(wp.name))) {
49        for (const member of wp.membersArray) {
50          // Member was overridden.
51          const memberId = member.kind + ':' + member.name;
52          if (membersMap.has(memberId))
53            continue;
54          membersMap.set(memberId, member);
55        }
56      }
57      return new Documentation.Class(cls.name, Array.from(membersMap.values()));
58    });
59  }
60
61
62  /**
63   * @param {!ts.Node} node
64   */
65  function visit(node) {
66    if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
67      const symbol = node.name ? checker.getSymbolAtLocation(node.name) : node.symbol;
68      let className = symbol.getName();
69
70      if (className === '__class') {
71        let parent = node;
72        while (parent.parent)
73          parent = parent.parent;
74        className = path.basename(parent.fileName,  '.js');
75      }
76      if (className && !excludeClasses.has(className)) {
77        classes.push(serializeClass(className, symbol, node));
78        const parentClassName = parentClass(node);
79        if (parentClassName)
80          inheritance.set(className, parentClassName);
81        excludeClasses.add(className);
82      }
83    }
84    ts.forEachChild(node, visit);
85  }
86
87  function parentClass(classNode) {
88    for (const herigateClause of classNode.heritageClauses || []) {
89      for (const heritageType of herigateClause.types) {
90        const parentClassName = heritageType.expression.escapedText;
91        return parentClassName;
92      }
93    }
94    return null;
95
96  }
97
98  function serializeSymbol(symbol, circular = []) {
99    const type = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
100    const name = symbol.getName();
101    if (symbol.valueDeclaration.dotDotDotToken) {
102      const innerType = serializeType(type.typeArguments[0], circular);
103      innerType.name = '...' + innerType.name;
104      return Documentation.Member.createProperty('...' + name, innerType);
105    }
106    return Documentation.Member.createProperty(name, serializeType(type, circular));
107  }
108
109  /**
110   * @param {!ts.ObjectType} type
111   */
112  function isRegularObject(type) {
113    if (type.isIntersection())
114      return true;
115    if (!type.objectFlags)
116      return false;
117    if (!('aliasSymbol' in type))
118      return false;
119    if (type.getConstructSignatures().length)
120      return false;
121    if (type.getCallSignatures().length)
122      return false;
123    return true;
124  }
125
126  /**
127   * @param {!ts.Type} type
128   * @return {!Documentation.Type}
129   */
130  function serializeType(type, circular = []) {
131    let typeName = checker.typeToString(type);
132    if (typeName === 'any' || typeName === '{ [x: string]: string; }')
133      typeName = 'Object';
134    const nextCircular = [typeName].concat(circular);
135
136    if (isRegularObject(type)) {
137      let properties = undefined;
138      if (!circular.includes(typeName))
139        properties = type.getProperties().map(property => serializeSymbol(property, nextCircular));
140      return new Documentation.Type('Object', properties);
141    }
142    if (type.isUnion() && typeName.includes('|')) {
143      const types = type.types.map(type => serializeType(type, circular));
144      const name = types.map(type => type.name).join('|');
145      const properties = [].concat(...types.map(type => type.properties));
146      return new Documentation.Type(name.replace(/false\|true/g, 'boolean'), properties);
147    }
148    if (type.typeArguments) {
149      const properties = [];
150      const innerTypeNames = [];
151      for (const typeArgument of type.typeArguments) {
152        const innerType = serializeType(typeArgument, nextCircular);
153        if (innerType.properties)
154          properties.push(...innerType.properties);
155        innerTypeNames.push(innerType.name);
156      }
157      if (innerTypeNames.length === 1 && innerTypeNames[0] === 'void')
158        return new Documentation.Type(type.symbol.name);
159      return new Documentation.Type(`${type.symbol.name}<${innerTypeNames.join(', ')}>`, properties);
160    }
161    return new Documentation.Type(typeName, []);
162  }
163
164  /**
165   * @param {string} className
166   * @param {!ts.Symbol} symbol
167   * @return {}
168   */
169  function serializeClass(className, symbol, node) {
170    /** @type {!Array<!Documentation.Member>} */
171    const members = classEvents.get(className) || [];
172
173    for (const [name, member] of symbol.members || []) {
174      if (name.startsWith('_'))
175        continue;
176      const memberType = checker.getTypeOfSymbolAtLocation(member, member.valueDeclaration);
177      const signature = memberType.getCallSignatures()[0];
178      if (signature)
179        members.push(serializeSignature(name, signature));
180      else
181        members.push(serializeProperty(name, memberType));
182    }
183
184    return new Documentation.Class(className, members);
185  }
186
187  /**
188   * @param {string} name
189   * @param {!ts.Signature} signature
190   */
191  function serializeSignature(name, signature) {
192    const parameters = signature.parameters.map(s => serializeSymbol(s));
193    const returnType = serializeType(signature.getReturnType());
194    return Documentation.Member.createMethod(name, parameters, returnType.name !== 'void' ? returnType : null);
195  }
196
197  /**
198   * @param {string} name
199   * @param {!ts.Type} type
200   */
201  function serializeProperty(name, type) {
202    return Documentation.Member.createProperty(name, serializeType(type));
203  }
204}
205
Full Screen

servicemanagementclient.js

Source: servicemanagementclient.js Github

copy
1/**
2* Copyright 2011 Microsoft Corporation
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*   http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16// Module dependencies.
17var https = require('https');
18var util = require('util');
19var fs = require('fs');
20var url = require('url');
21var tunnel = require('tunnel');
22var WebResource = require('../../http/webresource');
23var ServiceClient = require('./serviceclient');
24var Constants = require('../../util/constants');
25var HeaderConstants = Constants.HeaderConstants;
26
27
28// Expose 'ServiceManagementClient'.
29exports = module.exports = ServiceManagementClient;
30
31/**
32* Error messages.
33*/
34ServiceManagementClient.missingKeyValue = 'Client private key certificate is required';
35ServiceManagementClient.missingCertValue = 'Client public certificate is required';
36ServiceManagementClient.invalidSerializeType = 'serializetype must be XML or JSON';
37
38// Default API Version
39ServiceManagementClient.DefaultAPIVersion = '2012-03-01';
40// Default serialization Type: XML or JSON
41ServiceManagementClient.DefaultSerializeType = 'JSON';
42
43/**
44* Creates a new ServiceClient object.
45*
46* @constructor
47* @param {string} hostOptions             The host options to override defaults.
48*                                         {
49*                                            host: 'management.core.windows.net',
50*                                            port: optional port number
51*                                            apiversion: '2012-03-01',
52*                                            serializetype: 'XML'
53*                                         }
54*/
55function ServiceManagementClient(authentication, hostOptions) {
56  ServiceManagementClient.super_.call(this);
57  this._setAuthentication(authentication);
58  this._setServiceHost(hostOptions);
59  this._setDefaultProxy();
60}
61
62util.inherits(ServiceManagementClient, ServiceClient);
63
64/**
65* Sets the client authentication credentials using provided values
66* private key and public certificate values may be passed as strings, or will be read from files
67*
68* @return {Void}
69*/
70ServiceManagementClient.prototype._setAuthentication = function(authentication) {
71  this.keyvalue = null;
72  this.certvalue = null;
73
74  if (authentication) {
75    if (typeof authentication.keyvalue === 'string' && authentication.keyvalue.length > 0) {
76      this.keyvalue = authentication.keyvalue;
77    } else if (typeof authentication.keyfile === 'string' && authentication.keyfile.length > 0) {
78      this.keyvalue = fs.readFileSync(authentication.keyfile, 'ascii');
79    }
80    if (typeof authentication.certvalue === 'string' && authentication.certvalue.length > 0) {
81      this.certvalue = authentication.certvalue;
82    } else if (typeof authentication.certfile === 'string' && authentication.certfile.length > 0) {
83      this.certvalue = fs.readFileSync(authentication.certfile, 'ascii');
84    }
85  }
86
87  if (this.keyvalue === null || this.keyvalue.length === 0) {
88    var keyfile = process.env[ServiceClient.EnvironmentVariables.AZURE_KEYFILE];
89    if (typeof keyfile === 'string' && keyfile.length > 0) {
90      this.keyvalue = fs.readFileSync(keyfile, 'ascii');
91    }
92  }
93
94  if (this.certvalue === null || this.certvalue.length === 0) {
95    var certfile = process.env[ServiceClient.EnvironmentVariables.AZURE_CERTFILE];
96    if (typeof certfile === 'string' && certfile.length > 0) {
97      this.certvalue = fs.readFileSync(certfile, 'ascii');
98    }
99  }
100
101  if (this.keyvalue === null || this.keyvalue.length === 0) {
102    throw new Error(ServiceManagementClient.missingKeyValue);
103  }
104
105  if (this.certvalue === null || this.certvalue.length === 0) {
106    throw new Error(ServiceManagementClient.missingCertValue);
107  }
108};
109
110/**
111* Sets the service host options using provided values
112* Options are host name, serialization type, and API version string
113* If not specified, then the defaults are used
114*
115* @return {Void}
116*/
117ServiceManagementClient.prototype._setServiceHost = function(hostOptions) {
118  this.host = ServiceClient.CLOUD_SERVICE_MANAGEMENT_HOST;
119  this.apiversion = ServiceManagementClient.DefaultAPIVersion;
120  this.serializetype = ServiceManagementClient.DefaultSerializeType;
121  this.port = null;
122  this.protocol = Constants.HTTPS;
123
124  if (hostOptions) {
125    if (hostOptions.host) {
126      this.host = hostOptions.host;
127    }
128    if (hostOptions.apiversion) {
129      this.apiversion = hostOptions.apiversion;
130    }
131    if (hostOptions.serializetype) {
132      if (hostOptions.serializetype != 'XML' && hostOptions.serializetype != 'JSON') {
133        throw new Error(ServiceManagementClient.invalidSerializeType);
134      }
135      this.serializetype = hostOptions.serializetype;
136    }
137    if (hostOptions.port) {
138      this.port = hostOptions.port;
139    }
140  }
141};
142
143/**
144* Get the content-type string based on serializeType
145*
146* @return {string}
147*/
148ServiceManagementClient.prototype._getContentType = function() {
149  if (this.serializetype === 'XML') {
150    return 'application/xml';
151  } else {
152    return 'application/json';
153  }
154};
155
156/**
157* Get the accept header string based on serializeType
158*
159* @return {string}
160*/
161ServiceManagementClient.prototype._getAcceptType = function() {
162  if (this.serializetype === 'XML') {
163    return 'application/xml';
164  } else {
165    return 'application/json';
166  }
167};
168
169/**
170* Builds the request options to be passed to the http.request method.
171*
172* @param {WebResource} webResource The webresource where to build the options from.
173* @param {object}      options     The request options.
174* @param {function(error, requestOptions)}  callback  The callback function.
175* @return {undefined}
176*/
177ServiceManagementClient.prototype._buildRequestOptions = function(webResource, options, callback) {
178  var self = this;
179
180  webResource.addOptionalHeader(HeaderConstants.CONTENT_TYPE, self._getContentType());
181  webResource.addOptionalHeader(HeaderConstants.ACCEPT_HEADER, self._getAcceptType());
182  webResource.addOptionalHeader(HeaderConstants.ACCEPT_CHARSET_HEADER, 'UTF-8');
183  webResource.addOptionalHeader(HeaderConstants.STORAGE_VERSION_HEADER, self.apiversion);
184  webResource.addOptionalHeader(HeaderConstants.HOST_HEADER, self.host);
185
186  var requestOptions = null;
187  requestOptions = {
188    method: webResource.httpVerb,
189    path: webResource.path,
190    key: self.keyvalue,
191    cert: self.certvalue,
192    host: self.host,
193    headers: webResource.headers
194  };
195
196  if (self.port) {
197    requestOptions.port = self.port;
198  }
199
200  self._setAgent(self, requestOptions, self.protocol.substr(0, 5).toLowerCase() === Constants.HTTPS);
201  callback(null, requestOptions);
202};
203
204/**
205* Sets the service host default proxy from the environment.
206* Can be overridden by calling _setProxyUrl or _setProxy
207*
208*/
209ServiceManagementClient.prototype._setDefaultProxy = function() {
210  var proxyUrl = this._loadEnvironmentProxyValue();
211  this._setProxyUrl(proxyUrl);
212};
213
214/*
215* Sets proxy object from a proxy url.
216*
217* @param {string}   proxyurl     url of proxy server. ex: http:corpproxy:80
218*                                if null or undefined, clears proxy
219*/
220ServiceManagementClient.prototype._setProxyUrl = function(proxyurl) {
221  if (proxyurl) {
222    var parsedUrl = url.parse(proxyurl);
223    if (!parsedUrl.port) {
224      parsedUrl.port = 80;
225    }
226    this._setProxy({
227        host: parsedUrl.hostname,
228        port: parsedUrl.port
229      },
230      parsedUrl.protocol.substr(0, 5).toLowerCase() === Constants.HTTPS);
231  } else {
232    this._setProxy(null);
233  }
234};
235
236/*
237* Sets proxy object specified by caller.
238*
239* @param {object}   proxy       proxy to use for tunneling
240*                               {
241*                                host: hostname
242*                                port: port number
243*                                proxyAuth: 'user:password' for basic auth
244*                                headers: {...} headers for proxy server
245*                                key: key for proxy server
246*                                ca: ca for proxy server
247*                                cert: cert for proxy server
248*                               }
249*                               if null or undefined, clears proxy
250* @param {bool}     isHTTPS     true - use https to proxy. Otherwise use http.
251*/
252ServiceManagementClient.prototype._setProxy = function(proxy, isHTTPS) {
253  if (proxy) {
254    this.useTunnelProxy = true;
255    this.proxy = proxy;
256    this.proxyIsHTTPS = isHTTPS || false;
257  } else {
258    this.useTunnelProxy = false;
259    this.proxy = null;
260  }
261};
262
263/**
264* Set the Agent to use for the request
265*  Result depends on proxy settings and protocol
266*
267* @param {object}   reqopts     request options for request
268* @param {bool}     isHTTPS     true - use https to proxy. Otherwise use http.
269*/
270ServiceManagementClient.prototype._setAgent = function(self, reqopts, isHTTPS) {
271  if (self.useTunnelProxy && self.proxy) {
272    var agentinfo = {
273      proxy: self.proxy
274    };
275    if (reqopts.key) {
276      agentinfo.key = reqopts.key;
277    }
278    if (reqopts.cert) {
279      agentinfo.cert = reqopts.cert;
280    }
281    if (this.maxSockets) {
282      agentinfo.maxSockets = self.maxSockets;
283    }
284    if (isHTTPS) {
285      if (self.proxyIsHTTPS) {
286        reqopts.agent = tunnel.httpsOverHttps(agentinfo);
287      } else {
288        reqopts.agent = tunnel.httpsOverHttp(agentinfo);
289      }
290    } else {
291      if (self.proxyIsHTTPS) {
292        reqopts.agent = tunnel.httpOverHttps(agentinfo);
293      } else {
294        reqopts.agent = tunnel.httpOverHttp(agentinfo);
295      }
296    }
297  } else if (isHTTPS) {
298    reqopts.agent = new https.Agent(reqopts);
299  }
300};
Full Screen

generateApiJson.js

Source: generateApiJson.js Github

copy
1/**
2 * Copyright (c) Microsoft Corporation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// @ts-check
18
19const path = require('path');
20const fs = require('fs');
21const Documentation = require('./documentation');
22const { parseApi } = require('./api_parser');
23const PROJECT_DIR = path.join(__dirname, '..', '..');
24
25{
26  const documentation = parseApi(path.join(PROJECT_DIR, 'docs', 'src', 'api'));
27  documentation.setLinkRenderer(item => {
28    const { clazz, param, option } = item;
29    if (param)
30      return `\`${param}\``;
31    if (option)
32      return `\`${option}\``;
33    if (clazz)
34      return `\`${clazz.name}\``;
35  });
36  documentation.generateSourceCodeComments();
37  const result = serialize(documentation);
38  console.log(JSON.stringify(result));
39}
40
41/**
42 * @param {Documentation} documentation
43 */
44function serialize(documentation) {
45  return documentation.classesArray.map(serializeClass);
46}
47
48/**
49 * @param {Documentation.Class} clazz
50 */
51function serializeClass(clazz) {
52  const result = { name: clazz.name, spec: clazz.spec };
53  if (clazz.extends)
54    result.extends = clazz.extends;
55  result.langs = clazz.langs;
56  if (result.langs && result.langs.types) {
57    for (const key in result.langs.types)
58      result.langs.types[key] = serializeType(result.langs.types[key]);
59  }
60  if (clazz.comment)
61    result.comment = clazz.comment;
62  result.members = clazz.membersArray.map(serializeMember);
63  return result;
64}
65
66/**
67 * @param {Documentation.Member} member
68 */
69function serializeMember(member) {
70  const result = /** @type {any} */ ({ ...member });
71  sanitize(result);
72  result.args = member.argsArray.map(serializeProperty);
73  if (member.type)
74    result.type = serializeType(member.type)
75  return result;
76}
77
78function serializeProperty(arg) {
79  const result = { ...arg };
80  sanitize(result);
81  if (arg.type)
82    result.type = serializeType(arg.type, arg.name === 'options')
83  return result;
84}
85
86function sanitize(result) {
87  delete result.args;
88  delete result.argsArray;
89  delete result.clazz;
90  delete result.enclosingMethod;
91}
92
93/**
94 * @param {Documentation.Type} type
95 * @param {boolean} sortProperties
96 */
97function serializeType(type, sortProperties = false) {
98  /** @type {any} */
99  const result = { ...type };
100  if (type.properties)
101    result.properties = (sortProperties ? type.sortedProperties() : type.properties).map(serializeProperty);
102  if (type.union)
103    result.union = type.union.map(type => serializeType(type));
104  if (type.templates)
105    result.templates = type.templates.map(type => serializeType(type));
106  if (type.args)
107    result.args = type.args.map(type => serializeType(type));
108  if (type.returnType)
109    result.returnType = serializeType(type.returnType);
110  return result;
111}
112
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Playwright Internal on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)