How to use showSaveDialog method in Cypress

Best JavaScript code snippet using cypress

Run Cypress automation tests on LambdaTest cloud grid

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

DesignOne.js

Source: DesignOne.js Github

copy
1/* Get electron and fs functions */
2
3/* ES5 fsSource */
4// const fsSource = require('fs');
5/* ES5 fsSource */
6/* ES6 fsSource */
7import fsSource from 'fs';
8/* ES6 fsSource */
9
10// const electronSource = require('electron')
11// const { BrowserWindow, CurrentWindow, MessageWindow } = require('electron');
12// const { BrowserWindow, CurrentWindow } = require('electron')
13/* Original MessageWindow */
14// const {MessageWindow} = require('electron').remote;
15// const MessageWindow = electronSource.remote
16// const { MessageWindow } = electronSource.remote
17/* Original MessageWindow */
18// const {remote} = require('electron');
19// const {MessageWindow} = remote;
20
21/* ES5 BrowserWindow, CurrentWindow, MessageWindow */
22// const { BrowserWindow, CurrentWindow, MessageWindow } = require('electron').remote;
23/* ES5 BrowserWindow, CurrentWindow, MessageWindow */
24/* ES6 BrowserWindow, CurrentWindow, MessageWindow */
25import {BrowserWindow, CurrentWindow, MessageWindow} from ('electron').remote;
26/* ES6 BrowserWindow, CurrentWindow, MessageWindow */
27
28// const { dialog } = MessageWindow.dialog
29
30// BrowserWindow.showSaveDialog
31// CurrentWindow.showSaveDialog
32// MessageWindow.showSaveDialog
33// MessageWindow.showSaveDialog
34/* Get electron and fs functions */
35
36/* Get a Message Window from the Remote Module */
37
38/* Original eleDialog */
39// const { eleDialog } = electronSource.remote.dialog
40/* Original eleDialog */
41// const { eleDialog } = remote.dialog
42
43/* ES5 dialog, eleDialog */
44// const { dialog, eleDialog } = require("electron").remote;
45/* ES5 dialog, eleDialog */
46/* ES6 dialog, eleDialog */
47import {dialog, eleDialog} from ('electron').remote;
48/* ES6 dialog, eleDialog */
49
50/* ES5 fs */
51// const fs = require('fs');
52/* ES5 fs */
53/* ES6 fs */
54import fs from 'fs';
55/* ES6 fs */
56
57// var FileSavingPath = eleDialog.showSaveDialog({});
58// var FileOpenPath = eleDialog.showOpenDialog({});
59// eleDialog.properties
60
61// const { CurrentWindow, ChildWindow } = CurrentWindow.showSaveDialog
62// const { ChildWindow } = CurrentWindow.showSaveDialog
63// const { ChildWindow } = eleDialog.showSaveDialog
64// const { ChildWindow } = eleDialog.showSaveDialo
65
66// BrowserWindow.getCurrentWindow()
67/* Get a Message Window from the Remote Module */
68
69// from the document module of node
70// getElementById: Returns a reference to the first object with the specified value of the ID or NAME attribute.
71// Element.addEventListener
72
73
74document.getElementById("FirstClickArea").addEventListener
75// ("FirstClick", () => 
76// debugger;
77("click", () => 
78    {
79        // const LocalMessage = "*** Beginning of the Local Message ***";
80        const FirstClickAreaMsg = "[FirstClickArea Clicked]";
81        console.log(FirstClickAreaMsg);
82        // console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
83        console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
84        // MessageWindow.showSaveDialog.LocalMessage
85        // fsSource.writeFileSync()
86        // fsSource.writeSync()
87        // fsSource.writevSync()
88        // fsSource.WriteStream
89        // MessageWindow.showSaveDialog(
90            // eleDialog.showSaveDialog(
91        // CurrentWindow.CurrentWindow
92        // CurrentWindow.MessageWindow.showSaveDialog(
93
94        /* electron showMessageBox */
95        const options = {
96            type: 'question',
97            buttons: ['Cancel', 'Yes, please', 'No, thanks'],
98            defaultId: 2,
99            title: 'Question',
100            message: 'Do you want to do this?',
101            detail: 'It does not really matter',
102            checkboxLabel: 'Remember my answer',
103            checkboxChecked: true,
104          };
105        
106        MessageWindow.showMessageBox(null);
107        /* electron showMessageBox */
108
109        /* electron showSaveDialog */  
110        MessageWindow.showSaveDialog(
111            function (filename) {
112                    fsSource.writeFileSync(
113                        filename + ".txt", data, "utf-8", () => {
114                            console.log("Saving the File");
115                        }
116                    );
117                }
118        );
119        /* electron showSaveDialog */    
120
121    }
122);
123
124// const {CurrentWindow} = electronSource.getCurrentWindow()
125// electronSource.ClientRequest
126
127// document.getAnimations()
128// DocumentType.properties.remote
129document.getElementById("TurnOffApplication").addEventListener
130("click", () =>
131{
132    const TurnOffApplicationMsg = "[TurnOffApplicationMsg Clicked]";
133     console.log(TurnOffApplicationMsg);
134    // CurrentWindow.Close()
135    CurrentWindow.Closing()
136}
137);
138
Full Screen

api-dialog-spec.js

Source: api-dialog-spec.js Github

copy
1const assert = require('assert')
2const {dialog} = require('electron').remote
3
4describe('dialog module', () => {
5  describe('showOpenDialog', () => {
6    it('throws errors when the options are invalid', () => {
7      assert.throws(() => {
8        dialog.showOpenDialog({properties: false})
9      }, /Properties must be an array/)
10
11      assert.throws(() => {
12        dialog.showOpenDialog({title: 300})
13      }, /Title must be a string/)
14
15      assert.throws(() => {
16        dialog.showOpenDialog({buttonLabel: []})
17      }, /Button label must be a string/)
18
19      assert.throws(() => {
20        dialog.showOpenDialog({defaultPath: {}})
21      }, /Default path must be a string/)
22
23      assert.throws(() => {
24        dialog.showOpenDialog({message: {}})
25      }, /Message must be a string/)
26    })
27  })
28
29  describe('showSaveDialog', () => {
30    it('throws errors when the options are invalid', () => {
31      assert.throws(() => {
32        dialog.showSaveDialog({title: 300})
33      }, /Title must be a string/)
34
35      assert.throws(() => {
36        dialog.showSaveDialog({buttonLabel: []})
37      }, /Button label must be a string/)
38
39      assert.throws(() => {
40        dialog.showSaveDialog({defaultPath: {}})
41      }, /Default path must be a string/)
42
43      assert.throws(() => {
44        dialog.showSaveDialog({message: {}})
45      }, /Message must be a string/)
46
47      assert.throws(() => {
48        dialog.showSaveDialog({nameFieldLabel: {}})
49      }, /Name field label must be a string/)
50    })
51  })
52
53  describe('showMessageBox', () => {
54    it('throws errors when the options are invalid', () => {
55      assert.throws(() => {
56        dialog.showMessageBox(undefined, {type: 'not-a-valid-type'})
57      }, /Invalid message box type/)
58
59      assert.throws(() => {
60        dialog.showMessageBox(null, {buttons: false})
61      }, /Buttons must be an array/)
62
63      assert.throws(() => {
64        dialog.showMessageBox({title: 300})
65      }, /Title must be a string/)
66
67      assert.throws(() => {
68        dialog.showMessageBox({message: []})
69      }, /Message must be a string/)
70
71      assert.throws(() => {
72        dialog.showMessageBox({detail: 3.14})
73      }, /Detail must be a string/)
74
75      assert.throws(() => {
76        dialog.showMessageBox({checkboxLabel: false})
77      }, /checkboxLabel must be a string/)
78    })
79  })
80
81  describe('showErrorBox', () => {
82    it('throws errors when the options are invalid', () => {
83      assert.throws(() => {
84        dialog.showErrorBox()
85      }, /Insufficient number of arguments/)
86
87      assert.throws(() => {
88        dialog.showErrorBox(3, 'four')
89      }, /Error processing argument at index 0/)
90
91      assert.throws(() => {
92        dialog.showErrorBox('three', 4)
93      }, /Error processing argument at index 1/)
94    })
95  })
96
97  describe('showCertificateTrustDialog', () => {
98    it('throws errors when the options are invalid', () => {
99      assert.throws(() => {
100        dialog.showCertificateTrustDialog()
101      }, /options must be an object/)
102
103      assert.throws(() => {
104        dialog.showCertificateTrustDialog({})
105      }, /certificate must be an object/)
106
107      assert.throws(() => {
108        dialog.showCertificateTrustDialog({certificate: {}, message: false})
109      }, /message must be a string/)
110    })
111  })
112})
113
Full Screen

message-dialog.unit.test.js

Source: message-dialog.unit.test.js Github

copy
1'use strict';
2
3const messageDialog = require('../../../../../src/main-process/dialogs/message-dialog');
4
5describe('Testing message dialog', () => {
6  beforeEach(() => {
7    jest.clearAllMocks();
8  });
9
10  const fakeBrowserWindow = { msg: 'fakeBrowserWindow' };
11  const fakeElectronDialog = {
12    showOpenDialog: jest.fn(async () => ({ filePaths: ['/file/path'] })),
13    showSaveDialog: jest.fn(async () => ({ filePath: '/file/path' })),
14    showMessageBox: jest.fn(async () => {})
15  };
16
17  describe('Testing show open dialog', () => {
18    describe('When dialog is canceled', () => {
19      test('Should return empty object', async () => {
20        const fakeElectronDialog = {
21          showOpenDialog: jest.fn(async () => ({ canceled: true })),
22          showSaveDialog: jest.fn(async () => {}),
23          showMessageBox: jest.fn(async () => {})
24        };
25        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
26        const result = await msgDialog.showOpenDialog({ someOption: 'someValue' });
27        expect(result).toStrictEqual({});
28        expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
29        expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
30          { msg: 'fakeBrowserWindow' },
31          { someOption: 'someValue' }
32        );
33      });
34    });
35
36    describe('When dialog file path is not present', () => {
37      test('Should return empty object', async () => {
38        const fakeElectronDialog = {
39          showOpenDialog: jest.fn(async () => ({ filePaths: [] })),
40          showSaveDialog: jest.fn(async () => {}),
41          showMessageBox: jest.fn(async () => {})
42        };
43        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
44        const result = await msgDialog.showOpenDialog({ someOption: 'someValue' });
45        expect(result).toStrictEqual({});
46        expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
47        expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
48          { msg: 'fakeBrowserWindow' },
49          { someOption: 'someValue' }
50        );
51      });
52    });
53
54    describe('When dialog returned success', () => {
55      test('Should return filePath', async () => {
56        const fakeElectronDialog = {
57          showOpenDialog: jest.fn(async () => ({ filePaths: ['/file/path'] })),
58          showSaveDialog: jest.fn(async () => {}),
59          showMessageBox: jest.fn(async () => {})
60        };
61        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
62        const result = await msgDialog.showOpenDialog({ someOption: 'someValue' });
63        expect(result).toStrictEqual({ filePath: '/file/path' });
64        expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
65        expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
66          { msg: 'fakeBrowserWindow' },
67          { someOption: 'someValue' }
68        );
69      });
70    });
71  });
72
73  describe('Testing show save dialog', () => {
74    describe('When dialog is canceled', () => {
75      test('Should return empty object', async () => {
76        const fakeElectronDialog = {
77          showOpenDialog: jest.fn(async () => {}),
78          showSaveDialog: jest.fn(async () => ({ canceled: true })),
79          showMessageBox: jest.fn(async () => {})
80        };
81        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
82        const result = await msgDialog.showSaveDialog({ someOption: 'someValue' });
83        expect(result).toStrictEqual({});
84        expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
85        expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
86          { msg: 'fakeBrowserWindow' },
87          { someOption: 'someValue' }
88        );
89      });
90    });
91
92    describe('When dialog file path is not present', () => {
93      test('Should return empty object', async () => {
94        const fakeElectronDialog = {
95          showOpenDialog: jest.fn(async () => {}),
96          showSaveDialog: jest.fn(async () => ({})),
97          showMessageBox: jest.fn(async () => {})
98        };
99        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
100        const result = await msgDialog.showSaveDialog({ someOption: 'someValue' });
101        expect(result).toStrictEqual({});
102        expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
103        expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
104          { msg: 'fakeBrowserWindow' },
105          { someOption: 'someValue' }
106        );
107      });
108    });
109
110    describe('When dialog returned success', () => {
111      test('Should return filePath', async () => {
112        const fakeElectronDialog = {
113          showOpenDialog: jest.fn(async () => {}),
114          showSaveDialog: jest.fn(async () => ({ filePath: '/file/path' })),
115          showMessageBox: jest.fn(async () => {})
116        };
117        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
118        const result = await msgDialog.showSaveDialog({ someOption: 'someValue' });
119        expect(result).toStrictEqual({ filePath: '/file/path' });
120        expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
121        expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
122          { msg: 'fakeBrowserWindow' },
123          { someOption: 'someValue' }
124        );
125      });
126    });
127  });
128
129  describe('Testing show error dialog', () => {
130    describe('When there is no error message', () => {
131      test('Should call with generic error message', async () => {
132        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
133        await msgDialog.showErrorDialog({});
134        expect(fakeElectronDialog.showMessageBox).toHaveBeenCalledTimes(1);
135        expect(fakeElectronDialog.showMessageBox).toHaveBeenCalledWith(
136          { msg: 'fakeBrowserWindow' },
137          { message: 'Some error occurred!', type: 'error' }
138        );
139      });
140    });
141
142    describe('When there is specific error message', () => {
143      test('Should call with specific error message', async () => {
144        const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
145        await msgDialog.showErrorDialog({ message: 'This is specific error message.' });
146        expect(fakeElectronDialog.showMessageBox).toHaveBeenCalledTimes(1);
147        expect(fakeElectronDialog.showMessageBox).toHaveBeenCalledWith(
148          { msg: 'fakeBrowserWindow' },
149          { message: 'This is specific error message.', type: 'error' }
150        );
151      });
152    });
153  });
154
155  describe('Testing showOpenDialogToSelectJsonFile', () => {
156    test('Should be able to open dialog', async () => {
157      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
158      const result = await msgDialog.showOpenDialogToSelectJsonFile();
159      expect(result).toStrictEqual({ filePath: '/file/path' });
160      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
161      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
162        { msg: 'fakeBrowserWindow' },
163        {
164          filters: [{ extensions: ['json'], name: 'JSON' }],
165          properties: ['openFile', 'openDirectory']
166        }
167      );
168    });
169  });
170
171  describe('Testing showSaveDialogToSaveJsonFile', () => {
172    test('Should be able to open dialog', async () => {
173      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
174      const result = await msgDialog.showSaveDialogToSaveJsonFile();
175      expect(result).toStrictEqual({ filePath: '/file/path' });
176      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
177      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
178        { msg: 'fakeBrowserWindow' },
179        { filters: [{ extensions: ['json'], name: 'JSON' }], properties: ['openDirectory'] }
180      );
181    });
182  });
183
184  describe('Testing showOpenDialogToSelectXmlFile', () => {
185    test('Should be able to open dialog', async () => {
186      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
187      const result = await msgDialog.showOpenDialogToSelectXmlFile();
188      expect(result).toStrictEqual({ filePath: '/file/path' });
189      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
190      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
191        { msg: 'fakeBrowserWindow' },
192        {
193          filters: [{ extensions: ['xml'], name: 'XML' }],
194          properties: ['openFile', 'openDirectory']
195        }
196      );
197    });
198  });
199
200  describe('Testing showSaveDialogToSaveXmlFile', () => {
201    test('Should be able to open dialog', async () => {
202      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
203      const result = await msgDialog.showSaveDialogToSaveXmlFile();
204      expect(result).toStrictEqual({ filePath: '/file/path' });
205      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
206      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
207        { msg: 'fakeBrowserWindow' },
208        { filters: [{ extensions: ['xml'], name: 'XML' }], properties: ['openDirectory'] }
209      );
210    });
211  });
212
213  describe('Testing showOpenDialogToSelectFile', () => {
214    test('Should be able to open dialog', async () => {
215      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
216      const result = await msgDialog.showOpenDialogToSelectFile();
217      expect(result).toStrictEqual({ filePath: '/file/path' });
218      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
219      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
220        { msg: 'fakeBrowserWindow' },
221        {
222          properties: ['openFile', 'openDirectory']
223        }
224      );
225    });
226  });
227
228  describe('Testing showSaveDialogToSaveFile', () => {
229    test('Should be able to open dialog', async () => {
230      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
231      const result = await msgDialog.showSaveDialogToSaveFile();
232      expect(result).toStrictEqual({ filePath: '/file/path' });
233      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
234      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
235        { msg: 'fakeBrowserWindow' },
236        { properties: ['openDirectory'] }
237      );
238    });
239  });
240
241  describe('Testing showOpenDialogToSelectMarkdownFile', () => {
242    test('Should be able to open dialog', async () => {
243      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
244      const result = await msgDialog.showOpenDialogToSelectMarkdownFile();
245      expect(result).toStrictEqual({ filePath: '/file/path' });
246      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
247      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
248        { msg: 'fakeBrowserWindow' },
249        {
250          filters: [{ extensions: ['md', 'markdown'], name: 'Markdown' }],
251          properties: ['openFile', 'openDirectory']
252        }
253      );
254    });
255  });
256
257  describe('Testing showSaveDialogToSaveMarkdownFile', () => {
258    test('Should be able to open dialog', async () => {
259      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
260      const result = await msgDialog.showSaveDialogToSaveMarkdownFile();
261      expect(result).toStrictEqual({ filePath: '/file/path' });
262      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
263      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
264        { msg: 'fakeBrowserWindow' },
265        {
266          filters: [{ extensions: ['md', 'markdown'], name: 'Markdown' }],
267          properties: ['openFile', 'openDirectory']
268        }
269      );
270    });
271  });
272
273  describe('Testing showOpenDialogToSelectCanvasFile', () => {
274    test('Should be able to open dialog', async () => {
275      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
276      const result = await msgDialog.showOpenDialogToSelectCanvasFile();
277      expect(result).toStrictEqual({ filePath: '/file/path' });
278      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledTimes(1);
279      expect(fakeElectronDialog.showOpenDialog).toHaveBeenCalledWith(
280        { msg: 'fakeBrowserWindow' },
281        {
282          filters: [{ extensions: ['png'], name: 'Image' }],
283          properties: ['openFile', 'openDirectory']
284        }
285      );
286    });
287  });
288
289  describe('Testing showSaveDialogToSaveCanvasFile', () => {
290    test('Should be able to open dialog', async () => {
291      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
292      const result = await msgDialog.showSaveDialogToSaveCanvasFile();
293      expect(result).toStrictEqual({ filePath: '/file/path' });
294      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledTimes(1);
295      expect(fakeElectronDialog.showSaveDialog).toHaveBeenCalledWith(
296        { msg: 'fakeBrowserWindow' },
297        {
298          filters: [{ extensions: ['png'], name: 'Image' }],
299          properties: ['openFile', 'openDirectory']
300        }
301      );
302    });
303  });
304
305  describe('Testing showMessageBoxUnsavedChanges', () => {
306    test('Should be able to open dialog', async () => {
307      const fakeElectronDialog = {
308        showMessageBox: jest.fn(async () => ({ response: 0, checkboxChecked: false }))
309      };
310      const msgDialog = messageDialog(fakeBrowserWindow, fakeElectronDialog);
311      const result = await msgDialog.showMessageBoxUnsavedChanges({
312        type: 'question',
313        buttons: ['Save', 'Ignore changes', 'Cancel'],
314        message: 'Do you want to save the changes?'
315      });
316      expect(result).toStrictEqual({ response: 0, checkboxChecked: false });
317      expect(fakeElectronDialog.showMessageBox).toHaveBeenCalledTimes(1);
318      expect(fakeElectronDialog.showMessageBox).toHaveBeenCalledWith(
319        { msg: 'fakeBrowserWindow' },
320        {
321          type: 'question',
322          buttons: ['Save', 'Ignore changes', 'Cancel'],
323          message: 'Do you want to save the changes?'
324        }
325      );
326    });
327  });
328});
329
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 Cypress 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)