diff --git a/docs_source_files/content/webdriver/bidi_apis.de.md b/docs_source_files/content/webdriver/bidi_apis.de.md
new file mode 100644
index 000000000000..670976c35e78
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.de.md
@@ -0,0 +1,121 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+{{% notice %}}
+ Page being translated from
+English to German. Do you speak German? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.en.md b/docs_source_files/content/webdriver/bidi_apis.en.md
new file mode 100644
index 000000000000..d1365c623c4f
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.en.md
@@ -0,0 +1,116 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.es.md b/docs_source_files/content/webdriver/bidi_apis.es.md
new file mode 100644
index 000000000000..02b0770a6db3
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.es.md
@@ -0,0 +1,121 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+{{% notice %}}
+ Page being translated from
+English to Spanish. Do you speak Spanish? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.fr.md b/docs_source_files/content/webdriver/bidi_apis.fr.md
new file mode 100644
index 000000000000..802cc4b54218
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.fr.md
@@ -0,0 +1,122 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+
+{{% notice %}}
+ Page being translated from
+English to French. Do you speak French? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.ja.md b/docs_source_files/content/webdriver/bidi_apis.ja.md
new file mode 100644
index 000000000000..95db4b1d3a09
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.ja.md
@@ -0,0 +1,123 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+
+
+{{% notice %}}
+ Page being translated from
+English to Japanese. Do you speak Japanese? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.ko.md b/docs_source_files/content/webdriver/bidi_apis.ko.md
new file mode 100644
index 000000000000..4ab8bd91068a
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.ko.md
@@ -0,0 +1,123 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+
+
+{{% notice %}}
+ Page being translated from
+English to Korean. Do you speak Korean? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.nl.md b/docs_source_files/content/webdriver/bidi_apis.nl.md
new file mode 100644
index 000000000000..c30cee32752c
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.nl.md
@@ -0,0 +1,121 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+{{% notice %}}
+ Page being translated from
+English to Dutch. Do you speak Dutch? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.pt-br.md b/docs_source_files/content/webdriver/bidi_apis.pt-br.md
new file mode 100644
index 000000000000..2dc14ff23242
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.pt-br.md
@@ -0,0 +1,123 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+
+
+{{% notice %}}
+ Page being translated from
+English to Portuguese. Do you speak Portuguese? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}
diff --git a/docs_source_files/content/webdriver/bidi_apis.zh-cn.md b/docs_source_files/content/webdriver/bidi_apis.zh-cn.md
new file mode 100644
index 000000000000..e4bbf88fff80
--- /dev/null
+++ b/docs_source_files/content/webdriver/bidi_apis.zh-cn.md
@@ -0,0 +1,122 @@
+---
+title: "WebDriver Bidi APIs"
+weight: 3
+---
+
+{{% notice %}}
+ Page being translated from
+English to Simplified Chinese. Do you speak Simplified? Help us to translate
+it by sending us pull requests!
+{{% /notice %}}
+
+In Selenium 4, new Evented APIs were introduced that
+allow users to be able to capture events from the
+browser as they happen rather than using the
+traditional approach of Request/Response that
+WebDriver has used for other APIs.
+
+Internally WebDriver will create a WebSocket connection
+to the browser for events and commands to be transmitted.
+
+The following list of APIs will be growing as the Selenium
+project works through supporting real world use cases. If there
+is a missing API, please raise a [feature request](https://github.com/SeleniumHQ/selenium/issues/new?assignees=&labels=&template=feature.md).
+
+## Mutation Observation
+
+Mutation Observation is the ability to capture events via
+WebDriver BiDi when there are DOM mutations on a specific
+element in the DOM.
+
+{{< code-tab >}}
+ {{< code-panel language="java" >}}
+WebDriver driver = new FirefoxDriver();
+
+
+HasLogEvents logger = (HasLogEvents) driver;
+
+AtomicReference seen = new AtomicReference<>();
+CountDownLatch latch = new CountDownLatch(1);
+logger.onLogEvent(domMutation(mutation -> {
+ seen.set(mutation);
+ latch.countDown();
+}));
+
+driver.get("http://www.google.com");
+WebElement span = driver.findElement(By.cssSelector("span"));
+
+((JavascriptExecutor) driver).executeScript("arguments[0].setAttribute('cheese', 'gouda');", span);
+
+assertThat(latch.await(10, SECONDS)).isTrue();
+assertThat(seen.get().getAttributeName()).isEqualTo("cheese");
+assertThat(seen.get().getCurrentValue()).isEqualTo("gouda");
+
+
+ {{< / code-panel >}}
+ {{< code-panel language="python" >}}
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.wait import WebDriverWait
+
+driver = webdriver.Chrome()
+async with driver.log.mutation_events() as event:
+ pages.load("dynamic.html")
+ driver.find_element(By.ID, "reveal").click()
+ WebDriverWait(driver, 5)\
+ .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))
+
+assert event["attribute_name"] == "style"
+assert event["current_value"] == ""
+assert event["old_value"] == "display:none;"
+
+ {{< / code-panel >}}
+ {{< code-panel language="csharp" >}}
+IWebDriver driver = new FirefoxDriver();
+driver.Url = "http://www.google.com";
+// Please help with a .NET example
+ {{< / code-panel >}}
+ {{< code-panel language="ruby" >}}
+require 'selenium-webdriver'
+driver = Selenium::WebDriver.for :firefox
+begin
+ driver.on_log_event(:mutation) { |mutation| mutations.push(mutation) }
+ driver.navigate.to url_for('dynamic.html')
+ driver.find_element(id: 'reveal').click
+ wait.until { mutations.any? }
+ mutation = mutations.first
+ expect(mutation.element).to eq(driver.find_element(id: 'revealed'))
+ expect(mutation.attribute_name).to eq('style')
+ expect(mutation.current_value).to eq('')
+ expect(mutation.old_value).to eq('display:none;')
+ensure
+ driver.quit
+end
+ {{< / code-panel >}}
+ {{< code-panel language="javascript" >}}
+let {Builder, By} = require('selenium-webdriver');
+driver = new Builder().forBrowser('firefox').build();
+
+(async function test(){
+
+ const cdpConnection = await driver.createCDPConnection('page')
+ await driver.logMutationEvents(cdpConnection, function (event) {
+ assert.strictEqual(event['attribute_name'], 'style')
+ assert.strictEqual(event['current_value'], '')
+ assert.strictEqual(event['old_value'], 'display:none;')
+ })
+
+ await driver.get("https://www.google.com")
+
+ let element = driver.findElement({ id: 'reveal' })
+ await element.click()
+ let revealed = driver.findElement({ id: 'revealed' })
+ await driver.wait(until.elementIsVisible(revealed), 5000)
+
+})();
+ {{< / code-panel >}}
+ {{< code-panel language="kotlin" >}}
+val driver = FirefoxDriver()
+driver.get("http://www.google.com")
+// Please help us create an example for Kotlin
+ {{< / code-panel >}}
+{{< / code-tab >}}