Repository: microsoft/playwright-python

Issue:
[Question]: How to get the right BrowserType from a device name? 
### Your question

I noticed that the CLI is able to figure out the right `BrowserType` to use when it is launched from the command line:

```
playwright open --device="Desktop Safari" wikipedia.org  # Webkit
playwright open --device="Desktop Firefox" wikipedia.org  # Firefox
playwright open --device="Desktop Chrome" wikipedia.org  # Chrome
``` 

But [the documentation](https://playwright.dev/python/docs/api/class-playwright#playwright-devices) seems to say that I have to initialize a `BrowserType` before I can pass the settings to the context, which partially defeats the purpose of the device settings.

I can implement my own logic do initialize the right `BrowserType` for each device, but as `playwright open` can already do that, that seems superfluous.


Discussion:
You can get it from the `devices` object: https://playwright.dev/python/docs/emulation#devices. It's a property in the dict returned when you do `playwright.devices["Desktop Safari"]`
I can get the settings, but I still need to initialize a browser (`browser = await playwright.webkit.launch(headless=False)`), and then initialize the context (`context = await browser.new_context(**pixel_2)`). 

In my case, I want to start from the device name (say `'Pixel 2'`) and get the right `BrowserType`. And afaik, I can't figure that out without parsing the user agent, or manually mapping `'Pixel 2'` to `webkit` in my code.
Gotcha—looks like we are missing the defaultBrowserType property in the devices entries that are available in Node and could be used to programmatically pick `playwright.{webkit,chromium,firefox}`.

\o/ nice, thank you!
For now, you can get the defaultBrowserType from https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/deviceDescriptorsSource.json, but it should be exposed on `playwright.devices['Pixel 2']` in the future.
Excellent, I'll use the dump for now and switch to that when available.

Resolving patch:
diff --git a/playwright/_impl/_playwright.py b/playwright/_impl/_playwright.py
--- a/playwright/_impl/_playwright.py
+++ b/playwright/_impl/_playwright.py
@@ -81,4 +81,5 @@ def parse_device_descriptor(dict: Dict) -> Dict:
         "device_scale_factor": dict["deviceScaleFactor"],
         "is_mobile": dict["isMobile"],
         "has_touch": dict["hasTouch"],
+        "default_browser_type": dict["defaultBrowserType"],
     }


Test patch:
diff --git a/tests/async/test_device_descriptors.py b/tests/async/test_device_descriptors.py
new file mode 100644
--- /dev/null
+++ b/tests/async/test_device_descriptors.py
@@ -0,0 +1,37 @@
+import pytest
+
+
+@pytest.mark.only_browser("chromium")
+async def test_should_work(playwright) -> None:
+    device_descriptor = playwright.devices["Pixel 2"]
+    device_type = device_descriptor["default_browser_type"]
+    browser = await playwright[device_type].launch()
+    context = await browser.new_context(
+        **device_descriptor,
+    )
+    page = await context.new_page()
+    assert device_descriptor["default_browser_type"] == "chromium"
+    assert browser.browser_type.name == "chromium"
+
+    assert "Pixel 2" in device_descriptor["user_agent"]
+    assert "Pixel 2" in await page.evaluate("navigator.userAgent")
+
+    assert device_descriptor["device_scale_factor"] > 2
+    assert await page.evaluate("window.devicePixelRatio") > 2
+
+    assert device_descriptor["viewport"]["height"] > 700
+    assert device_descriptor["viewport"]["height"] < 800
+    inner_height = await page.evaluate("window.innerHeight")
+    inner_height > 700
+    inner_height < 800
+
+    assert device_descriptor["viewport"]["width"] > 400
+    assert device_descriptor["viewport"]["width"] < 500
+    inner_width = await page.evaluate("window.innerWidth")
+    inner_width > 400
+    inner_width < 500
+
+    assert device_descriptor["has_touch"]
+    assert device_descriptor["is_mobile"]
+
+    await browser.close()