How to use ConstructorCodeBuilder class of Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.CodeBuilders package

Best JustMockLite code snippet using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.CodeBuilders.ConstructorCodeBuilder

Run JustMockLite automation tests on LambdaTest cloud grid

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

ConstructorEmitter.cs

Source: ConstructorEmitter.cs Github

copy
1// Copyright 2004-2011 Castle Project - http://www.castleproject.org/
2// 
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// 
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
15namespace Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters
16{
17	using System;
18	using System.Reflection;
19	using System.Reflection.Emit;
20
21	using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.CodeBuilders;
22	using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.SimpleAST;
23
24	internal class ConstructorEmitter : IMemberEmitter
25	{
26		private readonly ConstructorBuilder builder;
27		private readonly AbstractTypeEmitter maintype;
28
29		private ConstructorCodeBuilder constructorCodeBuilder;
30
31		protected internal ConstructorEmitter(AbstractTypeEmitter maintype, ConstructorBuilder builder)
32		{
33			this.maintype = maintype;
34			this.builder = builder;
35		}
36
37		internal ConstructorEmitter(AbstractTypeEmitter maintype, params ArgumentReference[] arguments)
38		{
39			this.maintype = maintype;
40
41			var args = ArgumentsUtil.InitializeAndConvert(arguments);
42
43			builder = maintype.TypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, args);
44            // if we don't copy the parameter attributes, the default binder will fail
45            // when trying to resolve constructors from the passed argument values.
46            for (int i = 0; i < args.Length; ++i)
47            {
48                var arg = arguments[i];
49                var paramBuilder = builder.DefineParameter(i + 1, arg.ParameterAttributes, "");
50                if (arg.DefaultValue != DBNull.Value)
51                    paramBuilder.SetConstant(arg.DefaultValue);
52            }
53        }
54
55		public virtual ConstructorCodeBuilder CodeBuilder
56		{
57			get
58			{
59				if (constructorCodeBuilder == null)
60				{
61					constructorCodeBuilder = new ConstructorCodeBuilder(
62						maintype.BaseType, builder.GetILGenerator());
63				}
64				return constructorCodeBuilder;
65			}
66		}
67
68		public ConstructorBuilder ConstructorBuilder
69		{
70			get { return builder; }
71		}
72
73		public MemberInfo Member
74		{
75			get { return builder; }
76		}
77
78		public Type ReturnType
79		{
80			get { return typeof(void); }
81		}
82
83		private bool ImplementedByRuntime
84		{
85			get
86			{
87#if FEATURE_LEGACY_REFLECTION_API
88				var attributes = builder.GetMethodImplementationFlags();
89#else
90				var attributes = builder.MethodImplementationFlags;
91#endif
92				return (attributes & MethodImplAttributes.Runtime) != 0;
93			}
94		}
95
96		public virtual void EnsureValidCodeBlock()
97		{
98			if (ImplementedByRuntime == false && CodeBuilder.IsEmpty)
99			{
100				CodeBuilder.InvokeBaseConstructor();
101				CodeBuilder.AddStatement(new ReturnStatement());
102			}
103		}
104
105		public virtual void Generate()
106		{
107			if (ImplementedByRuntime)
108			{
109				return;
110			}
111
112			CodeBuilder.Generate(this, builder.GetILGenerator());
113		}
114	}
115}
Full Screen

ConstructorCodeBuilder.cs

Source: ConstructorCodeBuilder.cs Github

copy
1// Copyright 2004-2011 Castle Project - http://www.castleproject.org/
2// 
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// 
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
15namespace Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.CodeBuilders
16{
17	using System;
18	using System.Reflection;
19	using System.Reflection.Emit;
20
21	using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.SimpleAST;
22
23	internal class ConstructorCodeBuilder : AbstractCodeBuilder
24	{
25		private readonly Type baseType;
26
27		public ConstructorCodeBuilder(Type baseType, ILGenerator generator) : base(generator)
28		{
29			this.baseType = baseType;
30		}
31
32		public void InvokeBaseConstructor()
33		{
34			var type = baseType;
35			if (type.GetTypeInfo().ContainsGenericParameters)
36			{
37				type = type.GetGenericTypeDefinition();
38					// need to get generic type definition, otherwise the GetConstructor method might throw NotSupportedException
39			}
40
41			var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
42			var baseDefaultCtor = type.GetConstructor(flags, null, new Type[0], null);
43
44			InvokeBaseConstructor(baseDefaultCtor);
45		}
46
47		public void InvokeBaseConstructor(ConstructorInfo constructor)
48		{
49			AddStatement(new ConstructorInvocationStatement(constructor));
50		}
51
52		public void InvokeBaseConstructor(ConstructorInfo constructor, params ArgumentReference[] arguments)
53		{
54			AddStatement(
55				new ConstructorInvocationStatement(constructor,
56				                                   ArgumentsUtil.ConvertArgumentReferenceToExpression(arguments)));
57		}
58	}
59}
Full Screen

BaseProxyGenerator.cs

Source: BaseProxyGenerator.cs Github

copy
1// Copyright 2004-2011 Castle Project - http://www.castleproject.org/
2// 
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// 
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
15namespace Telerik.JustMock.Core.Castle.DynamicProxy.Generators
16{
17	using System;
18	using System.Collections.Generic;
19	using System.Diagnostics;
20	using System.Linq;
21	using System.Reflection;
22#if FEATURE_SERIALIZATION
23	using System.Runtime.Serialization;
24	using System.Xml.Serialization;
25#endif
26
27	using Telerik.JustMock.Core.Castle.Core.Logging;
28	using Telerik.JustMock.Core.Castle.DynamicProxy.Contributors;
29	using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters;
30	using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.CodeBuilders;
31	using Telerik.JustMock.Core.Castle.DynamicProxy.Generators.Emitters.SimpleAST;
32	using Telerik.JustMock.Core.Castle.DynamicProxy.Internal;
33    using Telerik.JustMock.Core.Castle.Core.Internal;
34
35#if NETCORE
36    using Debug = Telerik.JustMock.Diagnostics.JMDebug;
37#else
38using Debug = System.Diagnostics.Debug;
39#endif
40
41    /// <summary>
42    ///   Base class that exposes the common functionalities
43    ///   to proxy generation.
44    /// </summary>
45    internal abstract class BaseProxyGenerator
46	{
47		protected readonly Type targetType;
48		private readonly ModuleScope scope;
49		private ILogger logger = NullLogger.Instance;
50		private ProxyGenerationOptions proxyGenerationOptions;
51
52		protected BaseProxyGenerator(ModuleScope scope, Type targetType)
53		{
54			this.scope = scope;
55			this.targetType = targetType;
56		}
57
58		public ILogger Logger
59		{
60			get { return logger; }
61			set { logger = value; }
62		}
63
64		protected ProxyGenerationOptions ProxyGenerationOptions
65		{
66			get
67			{
68				if (proxyGenerationOptions == null)
69				{
70					throw new InvalidOperationException("ProxyGenerationOptions must be set before being retrieved.");
71				}
72				return proxyGenerationOptions;
73			}
74			set
75			{
76				if (proxyGenerationOptions != null)
77				{
78					throw new InvalidOperationException("ProxyGenerationOptions can only be set once.");
79				}
80				proxyGenerationOptions = value;
81			}
82		}
83
84		protected ModuleScope Scope
85		{
86			get { return scope; }
87		}
88
89		protected void AddMapping(Type @interface, ITypeContributor implementer, IDictionary<Type, ITypeContributor> mapping)
90		{
91			Debug.Assert(implementer != null, "implementer != null");
92			Debug.Assert(@interface != null, "@interface != null");
93			Debug.Assert(@interface.GetTypeInfo().IsInterface, "@interface.IsInterface");
94
95			if (!mapping.ContainsKey(@interface))
96			{
97				AddMappingNoCheck(@interface, implementer, mapping);
98			}
99		}
100
101#if FEATURE_SERIALIZATION
102		protected void AddMappingForISerializable(IDictionary<Type, ITypeContributor> typeImplementerMapping,
103		                                          ITypeContributor instance)
104		{
105			AddMapping(typeof(ISerializable), instance, typeImplementerMapping);
106		}
107#endif
108
109		/// <summary>
110		///   It is safe to add mapping (no mapping for the interface exists)
111		/// </summary>
112		/// <param name = "implementer"></param>
113		/// <param name = "interface"></param>
114		/// <param name = "mapping"></param>
115		protected void AddMappingNoCheck(Type @interface, ITypeContributor implementer,
116		                                 IDictionary<Type, ITypeContributor> mapping)
117		{
118			mapping.Add(@interface, implementer);
119		}
120
121		protected void AddToCache(CacheKey key, Type type)
122		{
123			scope.RegisterInCache(key, type);
124		}
125
126		protected virtual ClassEmitter BuildClassEmitter(string typeName, Type parentType, IEnumerable<Type> interfaces)
127		{
128			CheckNotGenericTypeDefinition(parentType, "parentType");
129			CheckNotGenericTypeDefinitions(interfaces, "interfaces");
130
131			return new ClassEmitter(Scope, typeName, parentType, interfaces);
132		}
133
134		protected void CheckNotGenericTypeDefinition(Type type, string argumentName)
135		{
136			if (type != null && type.GetTypeInfo().IsGenericTypeDefinition)
137			{
138				throw new ArgumentException("Type cannot be a generic type definition. Type: " + type.FullName, argumentName);
139			}
140		}
141
142		protected void CheckNotGenericTypeDefinitions(IEnumerable<Type> types, string argumentName)
143		{
144			if (types == null)
145			{
146				return;
147			}
148			foreach (var t in types)
149			{
150				CheckNotGenericTypeDefinition(t, argumentName);
151			}
152		}
153
154		protected void CompleteInitCacheMethod(ConstructorCodeBuilder constCodeBuilder)
155		{
156			constCodeBuilder.AddStatement(new ReturnStatement());
157		}
158
159		protected virtual void CreateFields(ClassEmitter emitter)
160		{
161			CreateOptionsField(emitter);
162			CreateSelectorField(emitter);
163			CreateInterceptorsField(emitter);
164		}
165
166		protected void CreateInterceptorsField(ClassEmitter emitter)
167		{
168			var interceptorsField = emitter.CreateField("__interceptors", typeof(IInterceptor[]));
169
170#if FEATURE_SERIALIZATION
171			emitter.DefineCustomAttributeFor<XmlIgnoreAttribute>(interceptorsField);
172#endif
173		}
174
175		protected FieldReference CreateOptionsField(ClassEmitter emitter)
176		{
177			return emitter.CreateStaticField("proxyGenerationOptions", typeof(ProxyGenerationOptions));
178		}
179
180		protected void CreateSelectorField(ClassEmitter emitter)
181		{
182			if (ProxyGenerationOptions.Selector == null)
183			{
184				return;
185			}
186
187			emitter.CreateField("__selector", typeof(IInterceptorSelector));
188		}
189
190		protected virtual void CreateTypeAttributes(ClassEmitter emitter)
191		{
192			emitter.AddCustomAttributes(ProxyGenerationOptions);
193#if FEATURE_SERIALIZATION
194			emitter.DefineCustomAttribute<XmlIncludeAttribute>(new object[] { targetType });
195#endif
196		}
197
198		protected void EnsureOptionsOverrideEqualsAndGetHashCode(ProxyGenerationOptions options)
199		{
200			if (Logger.IsWarnEnabled)
201			{
202				// Check the proxy generation hook
203				if (!OverridesEqualsAndGetHashCode(options.Hook.GetType()))
204				{
205					Logger.WarnFormat("The IProxyGenerationHook type {0} does not override both Equals and GetHashCode. " +
206					                  "If these are not correctly overridden caching will fail to work causing performance problems.",
207					                  options.Hook.GetType().FullName);
208				}
209
210				// Interceptor selectors no longer need to override Equals and GetHashCode
211			}
212		}
213
214		protected void GenerateConstructor(ClassEmitter emitter, ConstructorInfo baseConstructor,
215		                                   params FieldReference[] fields)
216        {
217            GenerateConstructor(emitter, baseConstructor, ProxyConstructorImplementation.CallBase, fields);
218        }
219
220        protected void GenerateConstructor(ClassEmitter emitter, ConstructorInfo baseConstructor,
221                                           ProxyConstructorImplementation impl, params FieldReference[] fields)
222        {
223            if (impl == ProxyConstructorImplementation.SkipConstructor)
224                return;
225
226            ArgumentReference[] args;
227			ParameterInfo[] baseConstructorParams = null;
228
229			if (baseConstructor != null)
230			{
231				baseConstructorParams = baseConstructor.GetParameters();
232			}
233
234			if (baseConstructorParams != null && baseConstructorParams.Length != 0)
235			{
236				args = new ArgumentReference[fields.Length + baseConstructorParams.Length];
237
238				var offset = fields.Length;
239				for (var i = offset; i < offset + baseConstructorParams.Length; i++)
240				{
241					var paramInfo = baseConstructorParams[i - offset];
242                    args[i] = new ArgumentReference(paramInfo.ParameterType, paramInfo.DefaultValue);
243                }
244			}
245			else
246			{
247				args = new ArgumentReference[fields.Length];
248			}
249
250			for (var i = 0; i < fields.Length; i++)
251			{
252				args[i] = new ArgumentReference(fields[i].Reference.FieldType);
253			}
254
255			var constructor = emitter.CreateConstructor(args);
256			if (baseConstructorParams != null && baseConstructorParams.Length != 0)
257			{
258                var last = baseConstructorParams.Last();
259                if (last.ParameterType.IsArray && last.IsDefined(typeof(ParamArrayAttribute)))
260                {
261                    var parameter = constructor.ConstructorBuilder.DefineParameter(args.Length, ParameterAttributes.None, last.Name);
262                    var builder = AttributeUtil.CreateBuilder<ParamArrayAttribute>();
263                    parameter.SetCustomAttribute(builder);
264                }
265            }
266
267			for (var i = 0; i < fields.Length; i++)
268			{
269				constructor.CodeBuilder.AddStatement(new AssignStatement(fields[i], args[i].ToExpression()));
270			}
271
272            // Invoke base constructor
273
274            if (impl == ProxyConstructorImplementation.CallBase)
275            {
276                if (baseConstructor != null)
277                {
278                    Debug.Assert(baseConstructorParams != null);
279
280                    var slice = new ArgumentReference[baseConstructorParams.Length];
281                    Array.Copy(args, fields.Length, slice, 0, baseConstructorParams.Length);
282
283                    constructor.CodeBuilder.InvokeBaseConstructor(baseConstructor, slice);
284                }
285                else
286                {
287                    constructor.CodeBuilder.InvokeBaseConstructor();
288                }
289            }
290
291			constructor.CodeBuilder.AddStatement(new ReturnStatement());
292		}
293
294		protected void GenerateConstructors(ClassEmitter emitter, Type baseType, params FieldReference[] fields)
295		{
296			var constructors =
297				baseType.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
298
299            var ctorGenerationHook = (ProxyGenerationOptions.Hook as IConstructorGenerationHook) ?? AllMethodsHook.Instance;
300            bool defaultCtorConsidered = false;
301            foreach (var constructor in constructors)
302            {
303                if (constructor.GetParameters().Length == 0)
304                    defaultCtorConsidered = true;
305
306                bool ctorVisible = IsConstructorVisible(constructor);
307                var analysis = new ConstructorImplementationAnalysis(ctorVisible);
308                var impl = ctorGenerationHook.GetConstructorImplementation(constructor, analysis);
309
310                GenerateConstructor(emitter, constructor, impl, fields);
311            }
312
313            if (!defaultCtorConsidered)
314            {
315                GenerateConstructor(emitter, null, ctorGenerationHook.DefaultConstructorImplementation, fields);
316            }
317        }
318
319		/// <summary>
320		///   Generates a parameters constructor that initializes the proxy
321		///   state with <see cref = "StandardInterceptor" /> just to make it non-null.
322		///   <para>
323		///     This constructor is important to allow proxies to be XML serializable
324		///   </para>
325		/// </summary>
326		protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseClass, FieldReference interceptorField)
327		{
328			// Check if the type actually has a default constructor
329			var defaultConstructor = baseClass.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes,
330			                                                  null);
331
332			if (defaultConstructor == null)
333			{
334				defaultConstructor = baseClass.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes,
335				                                              null);
336
337				if (defaultConstructor == null || defaultConstructor.IsPrivate)
338				{
339					return;
340				}
341			}
342
343			var constructor = emitter.CreateConstructor();
344
345			// initialize fields with an empty interceptor
346
347			constructor.CodeBuilder.AddStatement(new AssignStatement(interceptorField,
348			                                                         new NewArrayExpression(1, typeof(IInterceptor))));
349			constructor.CodeBuilder.AddStatement(
350				new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor), new Type[0])));
351
352			// Invoke base constructor
353
354			constructor.CodeBuilder.InvokeBaseConstructor(defaultConstructor);
355
356			constructor.CodeBuilder.AddStatement(new ReturnStatement());
357		}
358
359		protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter)
360		{
361			return emitter.CreateTypeConstructor();
362		}
363
364		protected Type GetFromCache(CacheKey key)
365		{
366			return scope.GetFromCache(key);
367		}
368
369		protected void HandleExplicitlyPassedProxyTargetAccessor(ICollection<Type> targetInterfaces,
370		                                                         ICollection<Type> additionalInterfaces)
371		{
372			var interfaceName = typeof(IProxyTargetAccessor).ToString();
373			//ok, let's determine who tried to sneak the IProxyTargetAccessor in...
374			string message;
375			if (targetInterfaces.Contains(typeof(IProxyTargetAccessor)))
376			{
377				message =
378					string.Format(
379						"Target type for the proxy implements {0} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?",
380						interfaceName);
381			}
382			else if (ProxyGenerationOptions.MixinData.ContainsMixin(typeof(IProxyTargetAccessor)))
383			{
384				var mixinType = ProxyGenerationOptions.MixinData.GetMixinInstance(typeof(IProxyTargetAccessor)).GetType();
385				message =
386					string.Format(
387						"Mixin type {0} implements {1} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to mix in an existing proxy?",
388						mixinType.Name, interfaceName);
389			}
390			else if (additionalInterfaces.Contains(typeof(IProxyTargetAccessor)))
391			{
392				message =
393					string.Format(
394						"You passed {0} as one of additional interfaces to proxy which is a DynamicProxy infrastructure interface and is implemented by every proxy anyway. Please remove it from the list of additional interfaces to proxy.",
395						interfaceName);
396			}
397			else
398			{
399				// this can technically never happen
400				message = string.Format("It looks like we have a bug with regards to how we handle {0}. Please report it.",
401				                        interfaceName);
402			}
403			throw new ProxyGenerationException("This is a DynamicProxy2 error: " + message);
404		}
405
406		protected void InitializeStaticFields(Type builtType)
407		{
408			builtType.SetStaticField("proxyGenerationOptions", BindingFlags.NonPublic, ProxyGenerationOptions);
409		}
410
411		protected Type ObtainProxyType(CacheKey cacheKey, Func<string, INamingScope, Type> factory)
412		{
413			Type cacheType;
414			using (var locker = Scope.Lock.ForReading())
415			{
416				cacheType = GetFromCache(cacheKey);
417				if (cacheType != null)
418				{
419					Logger.DebugFormat("Found cached proxy type {0} for target type {1}.", cacheType.FullName, targetType.FullName);
420					return cacheType;
421				}
422			}
423
424			// This is to avoid generating duplicate types under heavy multithreaded load.
425			using (var locker = Scope.Lock.ForWriting())
426			{
427				// Only one thread at a time may enter a write lock.
428				// See if an earlier lock holder populated the cache.
429				cacheType = GetFromCache(cacheKey);
430				if (cacheType != null)
431				{
432					Logger.DebugFormat("Found cached proxy type {0} for target type {1}.", cacheType.FullName, targetType.FullName);
433					return cacheType;
434				}
435
436				// Log details about the cache miss
437				Logger.DebugFormat("No cached proxy type was found for target type {0}.", targetType.FullName);
438				EnsureOptionsOverrideEqualsAndGetHashCode(ProxyGenerationOptions);
439
440				var name = Scope.NamingScope.GetUniqueName("Castle.Proxies." + targetType.Name + "Proxy");
441				var proxyType = factory.Invoke(name, Scope.NamingScope.SafeSubScope());
442
443				AddToCache(cacheKey, proxyType);
444				return proxyType;
445			}
446		}
447
448		private bool IsConstructorVisible(ConstructorInfo constructor)
449		{
450			 return constructor.IsPublic ||
451				constructor.IsFamily ||
452				constructor.IsFamilyOrAssembly ||
453				(constructor.IsAssembly && ProxyUtil.AreInternalsVisibleToDynamicProxy(constructor.DeclaringType.GetTypeInfo().Assembly));
454		}
455
456		private bool OverridesEqualsAndGetHashCode(Type type)
457		{
458			var equalsMethod = type.GetMethod("Equals", BindingFlags.Public | BindingFlags.Instance);
459			if (equalsMethod == null || equalsMethod.DeclaringType == typeof(object) || equalsMethod.IsAbstract)
460			{
461				return false;
462			}
463
464			var getHashCodeMethod = type.GetMethod("GetHashCode", BindingFlags.Public | BindingFlags.Instance);
465			if (getHashCodeMethod == null || getHashCodeMethod.DeclaringType == typeof(object) || getHashCodeMethod.IsAbstract)
466			{
467				return false;
468			}
469
470			return true;
471		}
472	}
473}
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

Most used methods in ConstructorCodeBuilder

Run Selenium Automation Tests on LambdaTest Cloud Grid

Trigger Selenium automation tests on a cloud-based Grid of 3000+ real browsers and operating systems.

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)