Conf42 JavaScript 2024 - Online

- premiere 5PM GMT

Playwright In An Hour

Abstract

The greatest web automation tool until the next one.

Summary

Transcript

This transcript was autogenerated. To make changes, submit a PR.
Hey everyone! Welcome to Conf42, the JavaScript version. I'm Gil and today we're going to talk about Playwright. It's called Playwright in an hour, hopefully less than an hour. It's an introduction of Playwright. If you don't know anything about web automation, cool I hope you get impressed by what Playwright can do. If you have experience with Selenium or Cypress or something like that's cool. And I'll talk about, my opinion about, what you should do if you do have experience and you have investment in, Cypress or Selenium or any other framework as well. Learn what it can do and then you can decide whether it can fit into what you're doing or not. I'm Gil, I'm a trainer and a consultant and I work with developers and testers who want to make software better. I'm the author of two books. This kind of thing, playwright, is something that is usually more connected with QA or testers. We think about is anything that's automating the web as something that automating the front end and we don't care about what is going on the back end. We'll talk about that too. but I find it also as a tool to help with developers. they can not only write unit tests. and test their own either components or backend, whatever they're testing, but also have some kind of mechanism to, do some end to end test and play right, fits right there. Apart from, doing some conferences like I do here, I also have a blog, a website, testingguild. com, and I post, videos on YouTube, on all kinds of things relating to testing. Testing and automation. So go check that out. So let's talk about a bit of history of where we are and how we got here. Playwright is a test framework, really. It started out as an automation tool, something as a project, internal project in Google that became Puppeteer, but it got stalled. And then, The developers got stolen. Microsoft decided to, do something with the knowledge that Puppeteer has behind it, which is a bad automation of the browser. they decided to build a whole test framework, for the web. so they got the knowledge, they got the people from Google, and they created Playwright, called Playwright. Launched in 2020. If you think about it, Selenium, Cypress are not full testing frameworks. So what does make a test framework? test framework, if you worked with Jasmine or Jest, you have something that identifies tests. when it says, test in the file or specs or something like that, and you have describe and you have it. So these are the keywords that identify tests. Apart from that, you have, registration. Registration is like the fancy name for when I asked run all the tests in this module, the test framework looks at the module, identifies all the testers, I need to run those. And if I do run all this testing module, except the one that starts with A, that's the registration part. And again, Jasmine, Jest, they do that. But if you look at Selenium, for example, it lives inside Test frameworks. It doesn't do that just does the automation apart from that. Obviously it runs the tests It reports the results obviously and have a bunch of asserts. We'll talk about that as well cypress has them has those if we worked with the unit test frameworks like for react or angular you know about jsdom which is a part of an engine that does identification and expects. So Cypress has those as well. Playwright has all of them. So it has a bit more, but it's a full test framework. Playwright comes with different flavors. So I'm going to show the JavaScript version today, where it started, but apart from that, it comes in Java and C sharp and Python. The main languages that you work with day to day, Playwright is there to help you. So how do you work? You install it through NPM. It's actually a two step install because Selenium today, but unlike Selenium a few years ago, it updates the driver's code. automatically. So you first need to install the pendency and then you have to run the playwright for the first time to download the drivers to run the thing. But then you're all set. What I'll also show you today is also working in VS Code and that means I also work with the extension and the extension has helped me do Things that usually I would have to do from the command line, which I still can do. So how does it work? Basically, what you have is, you have a server which produces some kind of HTML and JavaScript, and it runs in the browser. So far, welcome to the internet. You know how it works. If you want to automate that, then you have to have some kind of a test framework, a runner, a playwright, which runs a driver. This driver connects to the browser and can, Knows what the HTML, DOM is so it can query it and find things on it and run, JavaScript, scripts on it. That's basically it. That's what this web automation does anywhere. Playwright does it as well. So apart from that, it also works cross browser. So it supports the major browsers out there. I'm going to share with you today with Chrome, Windows, Slash edge, which is chromium, and it also works with Firefox and Safari as well. It has some mobile emulation features that you can specify like the viewports and geolocation. I'm not going to show you today, but it's a bit of a the thinking behind playwright about. Not just having a test framework, but like something that it's more of an end to end framework. We'll talk about that as well. Basically what we're going to write in the test is find what we call locators, things on the screen, and automate them. One thing to already mention, that's true not just for Playwright, but for other frameworks as well. When we are automating the browsers, we're running on two different processes. And that means we are sending messages from the Test framework to the browser, click this button. So it's not a synchronous command. Things will happen and then sometime in the future we'll get response. Yes, it got clicked. This asynchronicity is baked into playwright and we'll see that immediately, but we need to think about it and understand what does that mean. We can do something about the browser, but what happens on the backend is completely Out of our control. Okay, so let's start. I'm going to switch to VS Code. I'm running a local, as you can see, a local application that I wrote. It is a registration application, not a very smart one. It loads up like this with the first name, last name and email. Checkbox for I want to get promotions too. Unchecked for I have read the whole terms sheet and agree. Now, I'm if I have to check the term box in order to make this enabled, if I try to register with one of the boxes empty or with an invalid email, I'll get an error here, which was not the beginning. And if I type everything correctly, everybody loves live coding. So if I do that and press register, what happens that you don't see it here, but it redirects to another page tells me, thank you, Gil, first name. And it also stores these details in a JSON database locally. That's what it does. So we want to automate that. So before I jump here and show you the tests, I'm going to jump into the configuration file. you get a play rank, play right config, file, which you can define all the defaults there. I'm not going to go through everything, but what is interesting is the test deer, where it can find the tests. It looks for them, which you can put separately from the unit test that you're running or other tests that you're running. The base URL, which is currently a local host with port 3000, which is, will come in very handy in a minute. it tells other projects you'll have every browser that you want to run each test with. so I have Chromium on and I, commented out, Chrome, Safari, Edge, and the branded browsers. so when I run it once, but it can run, multiple times and web server, which is something interesting. A very cool feature I think is that, if you can't connect to a remote, server that's running, you're serving your web pages, You can run it locally or another web server, and it does this that if it finds it where you look for it, it will run against the remote server. I will run it locally, of course, but if it doesn't, it can fall back to a local server, start its own server, run the test, and then complete them and shut it down, which is very cool. I showed you the base URL because I'm going to use it in my Test so I have two tests here. you can see, I'm test here is not coming from anywhere else, but play right. It looks like jest or something like that. but it's not. So it's a test. The first test is, make sure that everything loads up correctly. You can see that it has a test name. Something very weird here injecting a page. object, which comes from Playwright as well. Now we start working with the page. The page is basically the main object that we're working with. we pay, do page go to, to navigate, and you see I'm using slash because I don't need to specify the base URL. It's in the config, so that's very cool. It makes a lot, the test a lot more readable. I don't need to return everything with, with every test. So I navigate to the page, find things, I am finding the welcome text here. this is, let's go back. This is the welcome text and the checkboxes and the buttons. And we'll talk about GetByText and GetByRole in a minute. And I'm expecting the title to be visible, promotions to be checked and the button to be disabled. If you work with Cypress, this looks very interesting. Similar to what we have here. Same with Js O, awaits because everything's going to be as synchronous, by default. Just works like that. For the next text, I have the registration process. I go to the pay CRL, find the things, the checkbox, the buttons, text boxes, and so on. Check the fo checkbox. 'cause I don't want, I want to enable the button, fill in the data. Click the button and you can see that when I click the button, remember it, never gets to another page. the page now at this line points to the next page to the current page. So there's no like interim thing. So the page will always point at the current page. I need to remember that as a doing thing. and expect the thank you message to be visible. If you worked with any automation framework before, this looks pretty good. Very similar. let me run this for you. First page, for example, I'm using the extension, this code extension, it translates this into a command line, it runs it, and you can see things are not running. And the reason that you don't see things running is because by default, Playwright runs in headless mode. And that means it doesn't open a browser, which is, talk about that too. It's a lot faster. Okay. How can I run it? I run it through the extension. I can run it from the command line, npx playwright test to run the tests. I can configure it with the configuration file. I can debug it, put a break point and, right click debug to debug it as debugging everything else. let me talk about the local. server, which is cool. How does it find things? So we already saw the get by role and stuff like that. I want to show you, these are the tests you saw that I'm using get by text and get by role. And there are different ways to find locators. I'm going to switch to my Browser. And these are the document. This is the documentation of playwright, from the internet. And this is the thing, but locator, you can see different ways to find locators now get by role is the. preferred way of finding things. other, we can find text by get by text or label by label, like placeholder for text boxes, alt text for images and so on. Test ID, if you use test IDs, data test IDs, it will find it for you. But the preferred way or recommended way is get by row. Why is it? first, what is it? Imagine that we have a button, right? The button that we have now. This can be implemented in different ways. It can be like an HTML button. Or it could be an image. It is like replaced when you click it. Or different ways. What I'm using in my application is a material UI, so it's a component of a button, which has like a border and stuff like that. It has a lot of things in it. So what specifies a button? the idea is that when the, we were trying to write a test as if the user was running them, and the user can identify buttons regardless of how they are implemented. getByRole means that find something that has a role of a button, which can be like a button or something with a role of a button, which, today in most frameworks that you work with, like react or view will create this code for you. So you're looking for the roles as if the user were looking for that. And then you will look, start looking for, things that, Even if they're not implemented as buttons, they will be. test IDs, for example, are not something that the user sees. These are things that are planted in the code by the developers, and they can break, and they will not, probably will not change, and there's a problem with dynamic elements, so it's still recommended to work with what the user sees. You can also scroll down. So if you're using CSS or XPath, you can still use those with the page. locator method. but again, apart from being pretty straightforward. Third and fourth languages, that you need to know after regular expressions, of course. These are hard to maintain or hard to read. And, while they are supported and sometimes you will need to use them, you probably want to use getByRule or getByText. So that's about locators. As we said, Playwright comes with a bunch of expects as well or assertions. Okay, what's next? Assertions. we talked about, the assertions that we have. If you're familiar with JSDOM and its assertions or Cypress, it has a lot of those as well. You're probably familiar with, expect something to be something. these are, The just things, for playwright, it comes with expect to have text and all these things here to be empty, to be editable, to be disabled, to be enabled. You can have to be visible and to be hidden. Makes sense. But you can also have a way to expect something. dot, not dot to be hidden, which is completely like to be visible. And personally, I don't like this redundancy, but it is there. So you can use not for, boolean things. If you used a locator to On multiple objects, it will find you those and then you can expect put in a certain the one that you're looking for, or all of them, and so on. That's basically it about locators and expects. So we talked about locators and expects. We saw that the tests were pretty readable. let's talk about what's cool. So one thing we already seen, running, with the browser hidden by default makes things faster. And I think this kind of speaks to the, Sort of philosophy of what's behind playwright and quick feedback is one of those. The idea is that we want to encourage the user, the writer, us, to run the test as much as possible and I think from my experience you can do that as long as you keep your test simple You can work without seeing what you're doing which is like a nice achievement for something that is a visual test framework. The next thing is something that if you're coming from Selenium, you might be aware slash afraid of, which is called stale elements. So in Selenium, if you find a locator or an element, you hold it in a variable and you can use it. Of course, but if the DOM changes, what you're holding is something that is stale. It no longer references. If you try to do something with it, click or query it, it will break. That will break. Playwright takes another different view of that. So it looks in my code. Remember, I put everything here to find the locators, and then I use it. them. And then what happens is the navigation and then page get by text, finding the message and doing that. So this is written in a way that makes sense. I go to a page, find everything on it, do stuff, navigate, find things on a page, the new one, and do something with it. But look at the magic. I can pass this line. Let's first run this to see that it works as it is. So there are no see I don't have anything in my sleeves. So this runs Excellent. It works. I can take this line here and just Move it up here. Okay, I haven't done anything but This looks weird right because it actually looks for something that is not there on the first page, but if I run it You'll see that it actually works How does it work? as opposed to holding something in my hand when I do get something by role or get by text when looking for a locator, what happens is that it doesn't actually look for the locator. Whenever I'm doing something with a locator, it will recalculate it. So what happens when it gets here, And it says, Oh, I need to do an expect with the thank you message. I need to find it first and see where it is now. And this is why it works because these just put a like a reminder when something look out for this, somebody will look for it later. And when you actually use it in one line, it will actually do that. This gives us something of an advantage in writing things. But for now, I'll just get it back here. Just to make sense. So locators are always calculated at the point where they are used. Now, remember asynchronicity? When I'm pressing the button, I'm not actually pressing the button, I'm passing a message to click the button. So what happens is that it will take time for the button to click, change how it looks, go from enable to disable. Lots of stuff happening. Like I said, until things happen. Now, what will happen if the button is not there? The idea Playwright takes is that it will probably be there in by in a few milliseconds or seconds Whatever you're doing is really timeout based. So let's look for example Remember when I'm opening the page, I want the title to be visible. Okay, let's inject some kind of an error in the test. Let's do put to be hidden, which of course will fail. And let's run it again and see what happens. Now you see, as I'm speaking, that it's waiting for it to be hidden, and it's waiting for a time out of five seconds. And it tells me, I waited five, 5, 000 seconds for that. I expect it to be hidden, but the final thing after five seconds was it was still visible. Now, that means that a lot of the errors that you will see or not, I expect this and receive this, which is what we're actually looking for, but timeout based things. So you have to get comfortable with this kind of error. The cool thing about, the 5, 000 millisecond delay is that it doesn't just sit there and wait. It does retries. Okay, so what we are calling, locators are really, auto wait locators. It actually waits for the locators by retrying and seeing if the status has changed. Okay, now remember the error I showed you? Let's see that again. If I click here, this is a dynamic error. It's not there at the beginning, but because of the way locators work, only at the point where I actually need to do something, I can write the test as if it was there in the beginning. So let's look at the errors. And you can see that it's completely the same. I have the error messages, even though they don't appear yet, on, they appear only after the click, but I can use them here. And I expect the error message to be visible. And the way it works is after I fill it up, it disappears. So I can check that it's hidden. Dynamic elements, Make sense in the way you actually use them and write them. There is something that you need to remember. That's not a playwright thing. It's a every test framework. Let me get back to here. So this checkbox enables and disables the button. . Okay. Now actually there, there is code that actually does this of course, but, semantically this enables it. This disables it. Remember that We don't see that in here. So I need to remember that when I do this, the checkbox check in the checkbox will actually enable the button so I can click it. So for me, I wrote it with a comment here. But if you don't do that, and I'll show you in a second where you don't do that, this kind of knowledge gets lost and you will lose it as you maintain these tests. If you look at this test, like three months from now, you won't even remember that the connection between the different components and you need to do something about it, rename stuff or put and to make you feel better when you're coming back to the test. Okay, so that was dynamic stuff and, let's talk about isolation. When I'm running the tests, each test runs in isolation. It actually opens a browser in incognito mode, so it doesn't have any cache, it doesn't have any cookies, starts from scratch, no history. And Playwright makes it that each test runs in isolation. Which is good. We want isolation because then we won't have tests running one on top of the other. We do have the ability to run, to open different pages, different browsers. So I want to show you this. Okay, so let's open Visual Studio Code and you'll see that I have two tests here. The first one runs opening the same page in the same browser. So let me run this and this time I'm going to go to the extension. And run it with the browsers. So I'm going to run this. Okay. As I run this, you'll see that a browser window opens. It's incognito. And I have two pages of the same application. This is good in the same browser window. Let me Close that and see what we have here. what we have here, instead of the page, I'm getting something called a context, browser context, which is basically a browser window. and you can see that I'm creating a new page, like a first page here, and I navigate, and then with the same context, I'm creating a second page. It does the same thing. to navigate here. So this is how I open two tabs inside a page. Both are isolated from each other. The second test does open two browser windows and in each one opens a page. So I can do that as well. This is different from Cypress, for example. Cypress runs inside the browser so it cannot navigate or open pages or open tabs. Playwright allows you to do that. It allows you to navigate forward. backwards and so on. Okay, so far we talked about the basic stuff, also some advanced stuff, but it's very cool because you can write a lot of tests, simple tests as you go through that. But like I said, Playwright sees itself as more than a web automation tool and it gives us a few features to work with that even better. The first one I'm going to show you is The code generation. Let me show you how it works. So Visual Studio. So what I'm going to do is run the code generation tool from the command line. I can do this also from the extension, but npx playwright code gen will run it. How does it look? So it opens up a browser window. So I'm going to mine it. application here. And let's say I am running very small test. So I'm going to click on this, you can see that it identifies where I'm standing, put something in the first name, and then I have a small ruler here with this one, assert text and assert value. So let's put an assert value with Gil in it. Okay, cool. Now, Let's look at what it created. So this is the playwright inspector. It's another window that is run by npx playwright. and it is where the code is generated for what I did. Now, remember what I did was clicking on the text box. First of all, writing the URL, entering the URL, clicking the text box and asserting that it has the value. So this is what I got. Now, as you can see, it's not perfect. First of all, The name it gives it is quite generic, but he couldn't really know it writes exactly what I typed, but it's not like the base URL when you're just putting the forward slash. Also, it identified the text box by using it by placeholder and not get by role of a text box, and it creates a lot of repeats of these things. the test It's okay. I can copy it into my suite. It works. Perfect. But in terms of maintainability, you'll create something that you probably don't want to hold on for a while. You want to refactor that, put the, find the text box by get by role, put it in a variable and reuse it later. Rename the test. The code gen tool actually works. It doesn't work. In a way that you'll probably want to keep this tested. So that means that whenever it creates something for you, you probably want to go in and refactor the tests. It is good for prototyping something. It is good for finding an elusive locator that you're looking for, but I found, but whenever I used it, it is a shortcut, but I had to go back and change a lot of the code. So that's the code gen tool. it also has a trace view, which you can debug whatever the whole, test that went through cool thing. I'm not going to show you, but you can look for it as well. I want to show you about APIs. And this is another thing that, like I said, the way The philosophy behind Playwright, which is, it's not just web automation, it's a whole system testing thing. And that is true. When you're testing a web frontend, at some point you'd like to at least check things that are not on the screen. if you entered my application saves data in the database so far apart from passing the information of the first name to the second page, you wouldn't know it, and the test frameworks cannot check it unless it has a name. Some kind of API access to the server, which it does. I wrote it. I wrote the server So I could write some code with the fetch or access to get to the server and find things but can do that Also with what gets provided with playwright because it has some API support in it, which is cool. So Let's look at that. Okay, so let's look at a test as you can see these things here Are completely the same as the visible stuff that we saw until now, it's the whole registration process, which is okay. I want to have that, as well, to make it past the test and, make sure that we're passing the entire, set of visible steps. But after that, I want to check that the data was actually saved through, in the server. And for that, I can use, like I said, Axios or, fetch, but I have request. Okay. Request from playwright, which is a wrapper for that as well. So it looks like using pages, right? Request a new context and I can get and post and delete stuff and I can use. the relative URL because I'm using the base URL, so it knows where I'm going. And after I do that, I get a JSON, and I can write some code to compare the JSON that I got with what I expect. this is the expect from, from Playwright, but it Again, it's a regular expected values, so it's not like comparing something on the browser, and therefore it doesn't have to be async. You don't have to wait for the result. very cool. This complementary, it completes the system testing framework. And the other thing is accessibility. Now, accessibility is very important, especially we're talking visual stuff that we're testing, it's a pass, it's possible to check for, whether it's the UI works for, people with disabilities out of the box. Playwright doesn't do that, but it integrates with a library called X that does that. let me show you. Okay, this will fail. So I put it in skip. Let me unskip it. And what I'm doing here is basically, using, XBuilder from the XCore dependency, but it has the integration with Playwright. And when I do that, I can write this. New XBuilder, initialize with a page, analyze. Now I have, let's uncomment this first. So what happens is that when we are doing analyze, it creates, it returns an error of violations. So if I run this, what will happen is that I actually get an error. Okay, because it found two violations. What are the violations? So I can actually Let's comment that so it will get to this line, rerun it again. And you'll see, what I got was, blah, blah, blah, blah, blah. element is It has insufficient color contrast element, must minimum color contrast ratio threshold. So it can, it brings you the whole library of accessibility rules that you can run on your application, different pages as part of your regression test with a couple of lines. It's very cool. Now, if you worked with Jest or Jasmine or worked with other frameworks in other languages, you probably saw that something was a bit different here with Playwright. And we don't have Describe or something like that. And that's not true. We do have, we want to group tests together. The default way is like putting things in a module and that kind of relate to each other. And since everything runs in isolation, you don't need to share information between tests. The describe doesn't make sense, but it is there. let's look at. So you can actually write test. describe, which has a test before each that runs before each and everything that you're used to before each, before all, after each, after all. You can actually write tests for And use the variable in context of the describe section and reuse them, So that's not going away. You still have that. And you can play with that as much as you want. Depending on the context of what is important for you, it will come out in the report as hierarchical results. Don't worry about that. What is interesting in Playwright and Canon U is the fixtures. Now, usually fixtures are We're thinking about in terms of test frameworks are the before each before also. We already seen that it's there, but these are not your ordinary fixtures. If you're familiar with test frameworks like PyTest or the fixture that we're going to show you here comes from, or in TestNG in Java, you'll know that apart from class tests like describes, you'll have something that you want to share across modules or classes. The idea is to share a common setup, not just in a file, across files. That's the idea. And what is this thing? This is code that runs before the test and after the test, right? If you go to the documentation, you'll see that both browser and context and page are already fixtures. But you can build your own fixture. So let's say, I'm going to show you an example with a page object. our registration, let's look at here. This is like how the code works, right? once you have the common locators here, you can write the tests without the common code. Makes sense. But it still looks like this. If you're using a page object model, a pattern which basically takes all the interaction with the page, the low level locator stuff and expects, you put it in a class and you expose that class and use it in the test, it will look a bit different. So I can write this page object, the register page, it, Gets the page in the constructor, has initialization and then type last name, type first name and so on. It wraps the operations by using the locators and operating them. If I do this, and I can do the same with the thank you page, in order to switch to the thank you page, I also have a submit thing which returns a thank you page. If I do that, my test will look like this. Thanks. Okay, creating the registration page, initialize, check the inbox, type in first name, last name, email, submit, get the thank you page, and thank you page has a verify message. And that's very cool, that doesn't have anything to do with fixtures, just hiding the low level information in the page object. But, let's use this page object in a fixture. first I have to write a fixture. this is a fixture, you can see that I have, a test which extends the register page. This is my code I have to write and within it I have some something weird. This is Creating the page object and then writing stuff that will happen as a common setup and then run the tests for the page and then run stuff under it. After that, I'm not using it right now, but this is the place to write the common cleanup. Once I have this, I can write this, which looks a lot like the test with playwright that we've seen before. I'm injecting the register page fixture. Everything hidden, the common setup, is out there. And look what I didn't show you. In the fixture itself, I have this. I have this line. Now, remember, let's say I have all kinds of tests I want to do with different inputs in the text boxes and so on. In all of them, I probably want to check the term box in order to enable the button. So this becomes like a common setup. It's not just like initializing. So if I want to do that, I can do that here. And now I can have multiple taps tests on different files that can use this fixture all starting when the button is already enabled. It is very cool. It can also be a bit confusing because you can play a lot with fixtures. They're cool. Don't get addicted to them. So is it good? first of all, it is good. It's a good framework. It's the cool kids on the block, but it is stable and it works. If you're starting out with web automation, I would take a hard look at Playwright and will probably tell you, you probably want to start. It has All the features that you want, it's complete. it gives you a complete solution. You don't have to look for anything else because the APIs are there. API supported there. Accessibility is there. So get a lot in the box, nothing. If you already have an investment in tests that you have a whole suite of tests with Selenium or Cypress or something else, I would still tell you, to look at the tool. To see if it works, you can always start writing the next tests with Playwright. But, to tell you to switch everything? No. Selenium is moving forward, Cypress is moving forward. I don't see why you should drop everything that you're doing, or invested until now, and change everything. For the new tool, because tomorrow there's going to be another new tool. Which is going to be cool, and you want to switch for that. Currently, I don't think that I would recommend leaving everything that you have. I would look at something that is maybe useful for the next thing that you're doing, an investor. The tests are shorter, they're more concise. It's up to you to make them a lot more readable. If you're using the code generator, you are responsible to actually making it readable for you and your users. future you and the other people on the team. it doesn't come out completely like that. If you are working with page objects, continue to work with page objects, fixtures, be careful with them because it is possible to overuse them, but they are useful. The final thing I want to say is that I also use them TDD test driven development, but more let's call it test first. It's not like TDD. So you, it is possible to write these tests up front and continue gradually adding elements to the screen and operating them. but it's not like regular TDD, so you probably, if you're like a TDD fanatic like me, you probably want to place the elements of the screen first before you start doing that, but after that you can add more steps, and making a test pass. So it is possible to use it for And that's what I wanted to share with you today. If you don't find me on discord or, the chat, you can find me on the internets, find me on YouTube with Dustin Gill, go to the site and, read what I blog about and have a nice con 42. Bye bye.
...

Gil Zilberfeld

CTO & CEO @ TestinGil

Gil Zilberfeld's LinkedIn account Gil Zilberfeld's twitter account



Awesome tech events for

Priority access to all content

Video hallway track

Community chat

Exclusive promotions and giveaways