How to use method of org.easymock.internal.MocksControl class

Best Easymock code snippet using org.easymock.internal.MocksControl.

Run Easymock automation tests on LambdaTest cloud grid

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

copy
1/*
2 * Copyright 2008, Unitils.org
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 * http://www.apache.org/licenses/LICENSE-2.0
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS,
9 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and
11 * limitations under the License.
12 */
13package org.unitils.easymock.util;
14
15import java.util.List;
16
17import org.easymock.IAnswer;
18import org.easymock.IArgumentMatcher;
19import org.easymock.internal.IMocksControlState;
20import org.easymock.internal.Invocation;
21import org.easymock.internal.LastControl;
22import org.easymock.internal.MocksControl;
23import org.easymock.internal.Range;
24import org.easymock.internal.RecordState;
25import org.unitils.reflectionassert.ReflectionComparatorMode;
26
27/**
28 * An EasyMock mock control that uses the reflection argument matcher for all arguments of a method invocation.
29 * <p/>
30 * No explicit argument matcher setting is needed (or allowed). This control will automatically report
31 * lenient reflection argument matchers. These matchers can apply some leniency when comparing expected and actual
32 * argument values.
33 * <p/>
34 * Setting the {@link ReflectionComparatorMode#IGNORE_DEFAULTS} mode will for example ignore all fields that
35 * have default values as expected values. E.g. if a null value is recorded as argument it will not be checked when
36 * the actual invocation occurs. The same applies for inner-fields of object arguments that contain default java values.
37 * <p/>
38 * Setting the {@link ReflectionComparatorMode#LENIENT_DATES} mode will ignore the actual date values of arguments and
39 * inner fields of arguments. It will only check whether both dates are null or both dates are not null. The actual
40 * date and hour do not matter.
41 * <p/>
42 * Setting the {@link ReflectionComparatorMode#LENIENT_ORDER} mode will ignore the actual order of collections and
43 * arrays arguments and inner fields of arguments. It will only check whether they both contain the same elements.
44 *
45 * @author Tim Ducheyne
46 * @author Filip Neven
47 * @see ReflectionComparatorMode
48 * @see org.unitils.reflectionassert.ReflectionComparator
49 */
50public class LenientMocksControl
51    extends MocksControl {
52    /***/
53    private static final long serialVersionUID = -4612378998272988410L;
54
55    /* The interceptor that wraps the record state */
56    private InvocationInterceptor invocationInterceptor;
57
58    /**
59     * Creates a default (no default returns and no order checking) mock control.
60     *
61     * @param modes
62     *     the modes for the reflection argument matcher
63     */
64    public LenientMocksControl(ReflectionComparatorMode... modes) {
65        this(org.easymock.MockType.DEFAULT, modes);
66    }
67
68    /**
69     * Creates a mock control.
70     * <ul>
71     * <li>Default mock type: no default return values and no order checking</li>
72     * <li>Nice mock type: returns default values if no return value set, no order checking</li>
73     * <li>Strict mock type: no default return values and strict order checking</li>
74     * </ul>
75     *
76     * @param type
77     *     the EasyMock mock type
78     * @param modes
79     *     the modes for the reflection argument matcher
80     */
81    public LenientMocksControl(org.easymock.MockType type, ReflectionComparatorMode... modes) {
82        super(type);
83        this.invocationInterceptor = new InvocationInterceptor(modes);
84    }
85
86    /**
87     * Overriden to be able to replace the record behavior that going to record all method invocations.
88     * The interceptor will make sure that reflection argument matchers will be reported for the
89     * arguments of all recorded method invocations.
90     *
91     * @return the state, wrapped in case of a RecordState
92     */
93    @Override
94    public IMocksControlState getState() {
95        IMocksControlState mocksControlState = super.getState();
96        if (mocksControlState instanceof RecordState) {
97            invocationInterceptor.setRecordState((RecordState) mocksControlState);
98            return invocationInterceptor;
99        }
100        return mocksControlState;
101    }
102
103    /**
104     * A wrapper for the record state in easy mock that will intercept the invoke method
105     * so that it can install reflection argument matchers for all arguments of the recorded method invocation.
106     * <p/>
107     * The old easy mock way of having a single argument matcher for all arguments has been deprecated. Since
108     * EasyMock 2 each argument should have its own matcher. We however want to avoid having to set all
109     * matchers to the reflection argument matcher explicitly.
110     * Because some of the methods are declared final and some classes explicitly cast to subtypes, creating a wrapper
111     * seems to be the only way to be able to intercept the matcher behavior.
112     */
113    private class InvocationInterceptor
114        implements IMocksControlState {
115
116        /* The wrapped record state */
117        private RecordState recordState;
118
119        /* The modes for the reflection argument matchers */
120        private ReflectionComparatorMode[] modes;
121
122        /**
123         * Creates an interceptor that will create reflection argument matchers for all arguments of all recorded
124         * method invocations.
125         *
126         * @param modes
127         *     the modes for the reflection argument matchers
128         */
129        public InvocationInterceptor(ReflectionComparatorMode... modes) {
130            this.modes = modes;
131        }
132
133        /**
134         * Sets the current wrapped record state.
135         *
136         * @param recordState
137         *     the state, not null
138         */
139        public void setRecordState(RecordState recordState) {
140            this.recordState = recordState;
141        }
142
143        /**
144         * Overriden to report reflection argument matchers for all arguments of the given method invocation.
145         *
146         * @param invocation
147         *     the method invocation, not null
148         * @return the result of the invocation
149         */
150        @Override
151        public Object invoke(Invocation invocation) {
152            LastControl.reportLastControl(LenientMocksControl.this);
153            createMatchers(invocation);
154            return recordState.invoke(invocation);
155        }
156
157        /**
158         * Reports report reflection argument matchers for all arguments of the given method invocation.
159         * An exception will be thrown if there were already matchers reported for the invocation.
160         *
161         * @param invocation
162         *     the method invocation, not null
163         */
164        private void createMatchers(Invocation invocation) {
165            List<IArgumentMatcher> matchers = LastControl.pullMatchers();
166            if (matchers != null && !matchers.isEmpty()) {
167                if (matchers.size() != invocation.getArguments().length) {
168                    throw new IllegalStateException("This mock control does not support mixing of no-argument matchers and per-argument matchers. "
169                        + "Either no matchers are defined and the reflection argument matcher is used by default or all matchers are defined explicitly (Eg by using refEq()).");
170                }
171                // put all matchers back since pull removes them
172                for (IArgumentMatcher matcher : matchers) {
173                    LastControl.reportMatcher(matcher);
174                }
175                return;
176            }
177            Object[] arguments = invocation.getArguments();
178            if (arguments == null) {
179                return;
180            }
181
182            for (Object argument : arguments) {
183                LastControl.reportMatcher(new ReflectionArgumentMatcher<>(argument, modes));
184            }
185        }
186
187        // Pass through delegation
188
189        @Override
190        public void assertRecordState() {
191            recordState.assertRecordState();
192        }
193
194        @Override
195        public void andReturn(Object value) {
196            recordState.andReturn(value);
197        }
198
199        @Override
200        public void andThrow(Throwable throwable) {
201            recordState.andThrow(throwable);
202        }
203
204        @Override
205        public void andAnswer(IAnswer<?> answer) {
206            recordState.andAnswer(answer);
207        }
208
209        @Override
210        public void andStubReturn(Object value) {
211            recordState.andStubReturn(value);
212        }
213
214        @Override
215        public void andStubThrow(Throwable throwable) {
216            recordState.andStubThrow(throwable);
217        }
218
219        @Override
220        public void andStubAnswer(IAnswer<?> answer) {
221            recordState.andStubAnswer(answer);
222        }
223
224        @Override
225        public void asStub() {
226            recordState.asStub();
227        }
228
229        @Override
230        public void times(Range range) {
231            recordState.times(range);
232        }
233
234        @Override
235        public void checkOrder(boolean value) {
236            recordState.checkOrder(value);
237        }
238
239        @Override
240        public void replay() {
241            recordState.replay();
242        }
243
244        @Override
245        public void verifyRecording() {
246            recordState.verifyRecording();
247        }
248
249        @Override
250        public void verifyUnexpectedCalls() {
251            recordState.verifyUnexpectedCalls();
252        }
253
254        @Override
255        public void verify() {
256            recordState.verify();
257        }
258
259        /*
260         * public void setDefaultReturnValue(Object value) {
261         * recordState.setDefaultReturnValue(value);
262         * }
263         * public void setDefaultThrowable(Throwable throwable) {
264         * recordState.setDefaultThrowable(throwable);
265         * }
266         * public void setDefaultVoidCallable() {
267         * recordState.setDefaultVoidCallable();
268         * }
269         * public void setDefaultMatcher(ArgumentsMatcher matcher) {
270         * recordState.setDefaultMatcher(matcher);
271         * }
272         * public void setMatcher(Method method, ArgumentsMatcher matcher) {
273         * recordState.setMatcher(method, matcher);
274         * }
275         */
276
277        /**
278         * @see org.easymock.internal.IMocksControlState#andDelegateTo(java.lang.Object)
279         */
280        @Override
281        public void andDelegateTo(Object value) {
282            recordState.andDelegateTo(value);
283        }
284
285        /**
286         * @see org.easymock.internal.IMocksControlState#andVoid()
287         */
288        @Override
289        public void andVoid() {
290            recordState.andVoid();
291        }
292
293        /**
294         * @see org.easymock.internal.IMocksControlState#andStubDelegateTo(java.lang.Object)
295         */
296        @Override
297        public void andStubDelegateTo(Object value) {
298            recordState.andStubDelegateTo(value);
299        }
300
301        /**
302         * @see org.easymock.internal.IMocksControlState#checkIsUsedInOneThread(boolean)
303         */
304        @Override
305        public void checkIsUsedInOneThread(boolean value) {
306            recordState.checkIsUsedInOneThread(value);
307        }
308
309        /**
310         * @see org.easymock.internal.IMocksControlState#makeThreadSafe(boolean)
311         */
312        @Override
313        public void makeThreadSafe(boolean value) {
314            recordState.makeThreadSafe(value);
315        }
316    }
317}
318
Full Screen
copy
1/*
2 * Copyright 2001-2021 the original author or authors.
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 */
16package org.easymock.internal;
17
18import org.easymock.ConstructorArgs;
19import org.easymock.EasyMock;
20import org.easymock.IAnswer;
21import org.easymock.IExpectationSetters;
22import org.easymock.IMocksControl;
23import org.easymock.MockType;
24
25import java.io.Serializable;
26import java.lang.reflect.InvocationHandler;
27import java.lang.reflect.Method;
28import java.lang.reflect.Proxy;
29import java.util.Arrays;
30import java.util.Set;
31
32/**
33 * @author OFFIS, Tammo Freese
34 */
35public class MocksControl implements IMocksControl, IExpectationSetters<Object>, Serializable {
36
37    private static final long serialVersionUID = 443604921336702014L;
38
39    /**
40     * Exactly one call.
41     */
42    public static final Range ONCE = new Range(1);
43
44    /**
45     * One or more calls.
46     */
47    public static final Range AT_LEAST_ONCE = new Range(1, Integer.MAX_VALUE);
48
49    /**
50     * Zero or more calls.
51     */
52    public static final Range ZERO_OR_MORE = new Range(0, Integer.MAX_VALUE);
53
54    /** lazily created; the proxy factory for classes */
55    private static volatile IProxyFactory classProxyFactory;
56
57    private static final IProxyFactory interfaceProxyFactory = new JavaProxyFactory();
58
59    private IMocksControlState state;
60
61    private IMocksBehavior behavior;
62
63    private MockType type;
64
65    public MocksControl(MockType type) {
66        this.type = type;
67        reset();
68    }
69
70    public MockType getType() {
71        return type;
72    }
73
74    public IMocksControlState getState() {
75        return state;
76    }
77
78    @Override
79    public <T, R> R createMock(Class<T> toMock) {
80        return createMock(null, toMock, null, (Method[]) null);
81    }
82
83    @Override
84    public <T, R> R createMock(String name, Class<T> toMock) {
85        return createMock(name, toMock, null, (Method[]) null);
86    }
87
88    @Override
89    public <T, R> R createMock(String name, Class<T> toMock, ConstructorArgs constructorArgs,
90            Method... mockedMethods) {
91        if (toMock == null) {
92            throw new NullPointerException("Can't mock 'null'");
93        }
94        // If we have mockedMethods, it means it's a partial mock. So it shouldn't be an interface that is mocked
95        // unless the interface has default methods and that it's some of these methods that are in mockedMethods
96        if (toMock.isInterface() && mockedMethods != null) {
97            checkInterfaceHasDefaultMethodAndIsMockingOnlyThem(toMock, mockedMethods);
98        }
99
100        try {
101            state.assertRecordState();
102            IProxyFactory proxyFactory = toMock.isInterface()
103                    ? interfaceProxyFactory
104                    : getClassProxyFactory();
105            try {
106                @SuppressWarnings("unchecked")
107                R mock = (R) proxyFactory.createProxy(toMock, new ObjectMethodsFilter(toMock,
108                    new MockInvocationHandler(this), name), mockedMethods, constructorArgs);
109                return mock;
110            } catch (NoClassDefFoundError e) {
111                if(e.getMessage().startsWith("org/objenesis")) {
112                    throw new RuntimeExceptionWrapper(new RuntimeException(
113                        "Class mocking requires to have Objenesis library in the classpath", e));
114                }
115                throw e;
116            }
117
118        } catch (RuntimeExceptionWrapper e) {
119            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
120        }
121    }
122
123    private <T> void checkInterfaceHasDefaultMethodAndIsMockingOnlyThem(Class<T> toMock, Method[] mockedMethods) {
124        Set<Method> defaultMethods = ReflectionUtils.getDefaultMethods(toMock);
125        if(defaultMethods.isEmpty()) {
126            throw new IllegalArgumentException("Partial mocking doesn't make sense for interface (" + toMock +  ") without default defaultMethods");
127        }
128        if(!defaultMethods.containsAll(Arrays.asList(mockedMethods))) {
129            throw new IllegalArgumentException("Mocking non-default method (one of " + Arrays.toString(mockedMethods)
130                + ") of an interface (" + toMock +  ")  doesn't make sense.");
131        }
132    }
133
134    public static IProxyFactory getProxyFactory(Object o) {
135        return Proxy.isProxyClass(o.getClass())
136                ? interfaceProxyFactory
137                : getClassProxyFactory();
138    }
139
140    private static IProxyFactory getClassProxyFactory() {
141        String classMockingDisabled = EasyMockProperties.getInstance().getProperty(
142                EasyMock.DISABLE_CLASS_MOCKING);
143        if (Boolean.parseBoolean(classMockingDisabled)) {
144            throw new IllegalArgumentException("Class mocking is currently disabled. Change "
145                    + EasyMock.DISABLE_CLASS_MOCKING + " to true do modify this behavior");
146        }
147
148        IProxyFactory cached = classProxyFactory;
149        if (cached != null) {
150            return cached;
151        }
152
153        // ///CLOVER:OFF
154        if (AndroidSupport.isAndroid()) {
155            return classProxyFactory = new AndroidClassProxyFactory();
156        }
157        // ///CLOVER:ON
158
159        return classProxyFactory = new ClassProxyFactory();
160    }
161
162    public static MocksControl getControl(Object mock) {
163        try {
164            IProxyFactory factory = getProxyFactory(mock);
165            ObjectMethodsFilter handler = (ObjectMethodsFilter) factory.getInvocationHandler(mock);
166            return handler.getDelegate().getControl();
167        } catch (ClassCastException e) {
168            throw new IllegalArgumentException("Not a mock: " + mock.getClass().getName());
169        }
170    }
171
172    public static InvocationHandler getInvocationHandler(Object mock) {
173        return getProxyFactory(mock).getInvocationHandler(mock);
174    }
175
176    /**
177     * Return the class of interface (depending on the mock type) that was
178     * mocked
179     *
180     * @param <T>
181     *            Mocked class
182     * @param <R>
183     *            Mock class
184     * @param proxy
185     *            Mock object
186     * @return the mocked class or interface
187     */
188    @SuppressWarnings("unchecked")
189    public static <T,  R extends T> Class<R> getMockedClass(T proxy) {
190        if (Proxy.isProxyClass(proxy.getClass())) {
191            return (Class<R>) proxy.getClass().getInterfaces()[0];
192        }
193        return (Class<R>) proxy.getClass().getSuperclass();
194    }
195
196    @Override
197    public void reset() {
198        behavior = new MocksBehavior(type == org.easymock.MockType.NICE);
199        behavior.checkOrder(type == org.easymock.MockType.STRICT);
200        state = new RecordState(behavior);
201        LastControl.reportLastControl(null);
202    }
203
204    @Override
205    public void resetToNice() {
206        type = MockType.NICE;
207        reset();
208    }
209
210    @Override
211    public void resetToDefault() {
212        type = MockType.DEFAULT;
213        reset();
214    }
215
216    @Override
217    public void resetToStrict() {
218        type = MockType.STRICT;
219        reset();
220    }
221
222    @Override
223    public void replay() {
224        try {
225            state.replay();
226            state = new ReplayState(behavior);
227            LastControl.reportLastControl(null);
228        } catch (RuntimeExceptionWrapper e) {
229            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
230        }
231    }
232
233    @Override
234    public void verifyRecording() {
235        try {
236            state.verifyRecording();
237        } catch (RuntimeExceptionWrapper e) {
238            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
239        } catch (AssertionErrorWrapper e) {
240            throw (AssertionError) e.getAssertionError().fillInStackTrace();
241        }
242    }
243
244    @Override
245    public void verifyUnexpectedCalls() {
246        try {
247            state.verifyUnexpectedCalls();
248        } catch (RuntimeExceptionWrapper e) {
249            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
250        } catch (AssertionErrorWrapper e) {
251            throw (AssertionError) e.getAssertionError().fillInStackTrace();
252        }
253    }
254
255    @Override
256    public void verify() {
257        try {
258            state.verify();
259        } catch (RuntimeExceptionWrapper e) {
260            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
261        } catch (AssertionErrorWrapper e) {
262            throw (AssertionError) e.getAssertionError().fillInStackTrace();
263        }
264    }
265
266    @Override
267    public void checkOrder(boolean value) {
268        try {
269            state.checkOrder(value);
270        } catch (RuntimeExceptionWrapper e) {
271            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
272        }
273    }
274
275    @Override
276    public void makeThreadSafe(boolean threadSafe) {
277        try {
278            state.makeThreadSafe(threadSafe);
279        } catch (RuntimeExceptionWrapper e) {
280            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
281        }
282    }
283
284    @Override
285    public void checkIsUsedInOneThread(boolean shouldBeUsedInOneThread) {
286        try {
287            state.checkIsUsedInOneThread(shouldBeUsedInOneThread);
288        } catch (RuntimeExceptionWrapper e) {
289            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
290        }
291    }
292
293    // methods from IBehaviorSetters
294
295    @Override
296    public IExpectationSetters<Object> andReturn(Object value) {
297        try {
298            state.andReturn(value);
299            return this;
300        } catch (RuntimeExceptionWrapper e) {
301            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
302        }
303    }
304
305    @Override
306    public IExpectationSetters<Object> andThrow(Throwable throwable) {
307        try {
308            state.andThrow(throwable);
309            return this;
310        } catch (RuntimeExceptionWrapper e) {
311            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
312        }
313    }
314
315    @Override
316    public IExpectationSetters<Object> andAnswer(IAnswer<?> answer) {
317        try {
318            state.andAnswer(answer);
319            return this;
320        } catch (RuntimeExceptionWrapper e) {
321            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
322        }
323    }
324
325    @Override
326    public IExpectationSetters<Object> andDelegateTo(Object answer) {
327        try {
328            state.andDelegateTo(answer);
329            return this;
330        } catch (RuntimeExceptionWrapper e) {
331            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
332        }
333    }
334
335    @Override
336    public IExpectationSetters<Object> andVoid() {
337        try {
338            state.andVoid();
339            return this;
340        } catch (RuntimeExceptionWrapper e) {
341            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
342        }
343    }
344
345    @Override
346    public void andStubReturn(Object value) {
347        try {
348            state.andStubReturn(value);
349        } catch (RuntimeExceptionWrapper e) {
350            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
351        }
352    }
353
354    @Override
355    public void andStubThrow(Throwable throwable) {
356        try {
357            state.andStubThrow(throwable);
358        } catch (RuntimeExceptionWrapper e) {
359            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
360        }
361    }
362
363    @Override
364    public void andStubAnswer(IAnswer<?> answer) {
365        try {
366            state.andStubAnswer(answer);
367        } catch (RuntimeExceptionWrapper e) {
368            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
369        }
370    }
371
372    @Override
373    public void andStubDelegateTo(Object delegateTo) {
374        try {
375            state.andStubDelegateTo(delegateTo);
376        } catch (RuntimeExceptionWrapper e) {
377            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
378        }
379    }
380
381    @Override
382    public void asStub() {
383        try {
384            state.asStub();
385        } catch (RuntimeExceptionWrapper e) {
386            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
387        }
388    }
389
390    @Override
391    public IExpectationSetters<Object> times(int times) {
392        try {
393            state.times(new Range(times));
394            return this;
395        } catch (RuntimeExceptionWrapper e) {
396            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
397        }
398    }
399
400    @Override
401    public IExpectationSetters<Object> times(int min, int max) {
402        try {
403            state.times(new Range(min, max));
404            return this;
405        } catch (RuntimeExceptionWrapper e) {
406            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
407        }
408    }
409
410    @Override
411    public IExpectationSetters<Object> once() {
412        try {
413            state.times(ONCE);
414            return this;
415        } catch (RuntimeExceptionWrapper e) {
416            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
417        }
418    }
419
420    @Override
421    public IExpectationSetters<Object> atLeastOnce() {
422        try {
423            state.times(AT_LEAST_ONCE);
424            return this;
425        } catch (RuntimeExceptionWrapper e) {
426            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
427        }
428    }
429
430    @Override
431    public IExpectationSetters<Object> anyTimes() {
432        try {
433            state.times(ZERO_OR_MORE);
434            return this;
435        } catch (RuntimeExceptionWrapper e) {
436            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
437        }
438    }
439
440}
441
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
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)