Fix onmounted event triggering many times (#3346)

* Fix event handler diffing

* Add headless tests for the onmounted event

* fix typo triggerd -> triggered
This commit is contained in:
Evan Almloff authored and GitHub committed 2024-12-17 15:21:15 -08:00
1 parent 01c5716128
commit c0e01f99af
8 files changed
+126 -38

No files matched your search

@@ -32,4 +32,8 @@ test("hydration", async ({ page }) => {
// Make sure the error that was thrown on the server is shown in the error boundary on the client
const errors = page.locator("#errors");
await expect(errors).toContainText("Hmm, something went wrong.");
// Expect the onmounted event to be called exactly once.
const mountedDiv = page.locator("div.onmounted-div");
await expect(mountedDiv).toHaveText("onmounted was called 1 times");
});
@@ -40,6 +40,21 @@ fn app() -> Element {
id: "errors",
Errors {}
}
OnMounted {}
}
}
#[component]
fn OnMounted() -> Element {
let mut mounted_triggered_count = use_signal(|| 0);
rsx! {
div {
class: "onmounted-div",
onmounted: move |_| {
mounted_triggered_count += 1;
},
"onmounted was called {mounted_triggered_count} times"
}
}
}
+45 -37
View File
@@ -1,72 +1,80 @@
// @ts-check
const { test, expect } = require('@playwright/test');
const { test, expect } = require("@playwright/test");
test('button click', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("button click", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the counter text.
const main = page.locator('#main');
await expect(main).toContainText('hello axum! 0');
const main = page.locator("#main");
await expect(main).toContainText("hello axum! 0");
// Click the increment button.
await page.getByRole('button', { name: 'Increment' }).click();
await page.getByRole("button", { name: "Increment" }).click();
// Expect the page to contain the updated counter text.
await expect(main).toContainText('hello axum! 1');
await expect(main).toContainText("hello axum! 1");
});
test('svg', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("svg", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the svg.
const svg = page.locator('svg');
const svg = page.locator("svg");
// Expect the svg to contain the circle.
const circle = svg.locator('circle');
await expect(circle).toHaveAttribute('cx', '50');
await expect(circle).toHaveAttribute('cy', '50');
await expect(circle).toHaveAttribute('r', '40');
await expect(circle).toHaveAttribute('stroke', 'green');
await expect(circle).toHaveAttribute('fill', 'yellow');
const circle = svg.locator("circle");
await expect(circle).toHaveAttribute("cx", "50");
await expect(circle).toHaveAttribute("cy", "50");
await expect(circle).toHaveAttribute("r", "40");
await expect(circle).toHaveAttribute("stroke", "green");
await expect(circle).toHaveAttribute("fill", "yellow");
});
test('raw attribute', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("raw attribute", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the div with the raw attribute.
const div = page.locator('div.raw-attribute-div');
await expect(div).toHaveAttribute('raw-attribute', 'raw-attribute-value');
const div = page.locator("div.raw-attribute-div");
await expect(div).toHaveAttribute("raw-attribute", "raw-attribute-value");
});
test('hidden attribute', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("hidden attribute", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the div with the hidden attribute.
const div = page.locator('div.hidden-attribute-div');
await expect(div).toHaveAttribute('hidden', 'true');
const div = page.locator("div.hidden-attribute-div");
await expect(div).toHaveAttribute("hidden", "true");
});
test('dangerous inner html', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("dangerous inner html", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the div with the dangerous inner html.
const div = page.locator('div.dangerous-inner-html-div');
await expect(div).toContainText('hello dangerous inner html');
const div = page.locator("div.dangerous-inner-html-div");
await expect(div).toContainText("hello dangerous inner html");
});
test('input value', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("input value", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the input with the value.
const input = page.locator('input');
await expect(input).toHaveValue('hello input');
const input = page.locator("input");
await expect(input).toHaveValue("hello input");
});
test('style', async ({ page }) => {
await page.goto('http://127.0.0.1:3030');
test("style", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the page to contain the div with the style.
const div = page.locator('div.style-div');
await expect(div).toHaveText('colored text');
await expect(div).toHaveCSS('color', 'rgb(255, 0, 0)');
const div = page.locator("div.style-div");
await expect(div).toHaveText("colored text");
await expect(div).toHaveCSS("color", "rgb(255, 0, 0)");
});
test("onmounted", async ({ page }) => {
await page.goto("http://127.0.0.1:3030");
// Expect the onmounted event to be called exactly once.
const mountedDiv = page.locator("div.onmounted-div");
await expect(mountedDiv).toHaveText("onmounted was called 1 times");
});
@@ -20,6 +20,21 @@ fn app() -> Element {
}
input { value: "hello input" }
div { class: "style-div", color: "red", "colored text" }
OnMounted {}
}
}
#[component]
fn OnMounted() -> Element {
let mut mounted_triggered_count = use_signal(|| 0);
rsx! {
div {
class: "onmounted-div",
onmounted: move |_| {
mounted_triggered_count += 1;
},
"onmounted was called {mounted_triggered_count} times"
}
}
}
+8
View File
@@ -107,3 +107,11 @@ test("prevent default", async ({ page }) => {
// Check that the <a> element changed.
await expect(a).toHaveText("Psych!");
});
test("onmounted", async ({ page }) => {
await page.goto("http://localhost:9999");
// Expect the onmounted event to be called exactly once.
const mountedDiv = page.locator("div.onmounted-div");
await expect(mountedDiv).toHaveText("onmounted was called 1 times");
});
+15
View File
@@ -52,6 +52,7 @@ fn app() -> Element {
}
div { class: "eval-result", "{eval_result}" }
PreventDefault {}
OnMounted {}
}
}
@@ -71,6 +72,20 @@ fn PreventDefault() -> Element {
}
}
#[component]
fn OnMounted() -> Element {
let mut mounted_triggered_count = use_signal(|| 0);
rsx! {
div {
class: "onmounted-div",
onmounted: move |_| {
mounted_triggered_count += 1;
},
"onmounted was called {mounted_triggered_count} times"
}
}
}
fn main() {
tracing_wasm::set_as_global_default_with_config(
tracing_wasm::WASMLayerConfigBuilder::default()