diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index c01acd67c9..7070c992fe 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -805,7 +805,9 @@ patch: ${JSON.stringify( const set_waiting = () => { let from_update = message?.response?.update_went_well != null let is_just_acknowledgement = from_update && message.patches.length === 0 - // console.log("Received patches!", message.patches, message.response, is_just_acknowledgement) + let is_relevant_for_bonds = message.patches.some(({ path }) => path.length === 0 || path[0] !== "status_tree") + + // console.debug("Received patches!", is_just_acknowledgement, is_relevant_for_bonds, message.patches, message.response) if (!is_just_acknowledgement) { this.waiting_for_bond_to_trigger_execution = false diff --git a/src/evaluation/Run.jl b/src/evaluation/Run.jl index 81be9f736b..ae1d223578 100644 --- a/src/evaluation/Run.jl +++ b/src/evaluation/Run.jl @@ -57,6 +57,9 @@ function run_reactive_core!( old_workspace_name, _ = WorkspaceManager.bump_workspace_module((session, notebook)) + # A state sync will come soon from this function, so let's delay anything coming from the status_tree listener, see https://github.com/fonsp/Pluto.jl/issues/2978 + Throttled.force_throttle_without_run(notebook.status_tree.update_listener_ref[]) + run_status = Status.report_business_started!(notebook.status_tree, :run) Status.report_business_started!(run_status, :resolve_topology) cell_status = Status.report_business_planned!(run_status, :evaluate) diff --git a/test/frontend/__tests__/bonds.js b/test/frontend/__tests__/bonds.js index af633a3400..0050429d45 100644 --- a/test/frontend/__tests__/bonds.js +++ b/test/frontend/__tests__/bonds.js @@ -1,9 +1,18 @@ import puppeteer from "puppeteer" -import { saveScreenshot, createPage, paste } from "../helpers/common" -import { createNewNotebook, getPlutoUrl, runAllChanged, setupPlutoBrowser, shutdownCurrentNotebook, waitForPlutoToCalmDown } from "../helpers/pluto" +import { saveScreenshot, createPage, paste, waitForContentToBecome, waitForContent } from "../helpers/common" +import { + createNewNotebook, + getPlutoUrl, + importNotebook, + runAllChanged, + setupPlutoBrowser, + shutdownCurrentNotebook, + waitForCellOutput, + waitForPlutoToCalmDown, +} from "../helpers/pluto" // https://github.com/fonsp/Pluto.jl/issues/928 -describe("Bonds should run once when refreshing page", () => { +describe("@bind", () => { /** * Launch a shared browser instance for all tests. * I don't use jest-puppeteer because it takes away a lot of control and works buggy for me, @@ -78,4 +87,55 @@ numberoftimes = Ref(0) }) expect(output_after_reload).toBe(output_after_running_bonds) }) + + it("should ignore intermediate bond values while the notebook is running", async () => { + const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + + const chill = async () => { + await wait(300) + await waitForPlutoToCalmDown(page) + await wait(1500) + await waitForPlutoToCalmDown(page) + } + + await importNotebook(page, "test_bind_dynamics.jl") + await chill() + await chill() + + const id = `029e1d1c-bf42-4e2c-a141-1e2eecc0800d` + const output_selector = `pluto-cell[id="${id}"] pluto-output` + + //page.click is stupid + const click = async (sel) => { + await page.waitForSelector(sel) + await page.evaluate((sel) => document.querySelector(sel).click(), sel) + } + + const reset = async () => { + await click(`#reset_xs_button`) + await wait(300) + await waitForPlutoToCalmDown(page) + await waitForContentToBecome(page, output_selector, "") + await wait(300) + await waitForPlutoToCalmDown(page) + await waitForContentToBecome(page, output_selector, "") + await wait(300) + } + + const start = async () => { + await click(`#add_x_button`) + await chill() + + return await waitForContent(page, output_selector) + } + + await reset() + await start() + + await chill() + + await reset() + const val = await start() + expect(val).toBe("1,done") + }) }) diff --git a/test/frontend/fixtures/test_bind_dynamics.jl b/test/frontend/fixtures/test_bind_dynamics.jl new file mode 100644 index 0000000000..0746d5c805 --- /dev/null +++ b/test/frontend/fixtures/test_bind_dynamics.jl @@ -0,0 +1,91 @@ +### A Pluto.jl notebook ### +# v0.19.45 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) + el + end +end + +# ╔═╡ a0fe4e4d-eee5-4420-bd58-3f12749a9ed1 +@bind reset_xs html"" + +# ╔═╡ 58db6bd4-58a6-11ef-3795-fd6e57eceb68 +@bind x html"""
+ + +
""" + +# ╔═╡ 8568c646-0233-4a95-8332-2351e9c56027 +@bind withsleep html"" + +# ╔═╡ 8a20fa4a-ac02-4a37-a54e-e4224628db66 +x + +# ╔═╡ 29f1d840-574e-463c-87d3-4b938e123493 +begin + reset_xs + xs = [] +end + +# ╔═╡ 3155b6e0-8e19-4583-b2ab-4ab2db1f10b9 +md""" +Click **reset_xs**. + +Click **Start**. + +The cell below should give: `1,done`. + +Not: `1,2,done` or something like that. That means that an intermediate bond value (`2`) found its way through: [https://github.com/fonsp/Pluto.jl/issues/1891](https://github.com/fonsp/Pluto.jl/issues/1891) +""" + +# ╔═╡ 029e1d1c-bf42-4e2c-a141-1e2eecc0800d +begin + withsleep && sleep(1.5) + push!(xs, x) + xs_done = true + + join(xs[2:end], ",") |> Text +end + +# ╔═╡ Cell order: +# ╟─a0fe4e4d-eee5-4420-bd58-3f12749a9ed1 +# ╟─58db6bd4-58a6-11ef-3795-fd6e57eceb68 +# ╟─8568c646-0233-4a95-8332-2351e9c56027 +# ╠═8a20fa4a-ac02-4a37-a54e-e4224628db66 +# ╟─3155b6e0-8e19-4583-b2ab-4ab2db1f10b9 +# ╠═029e1d1c-bf42-4e2c-a141-1e2eecc0800d +# ╠═29f1d840-574e-463c-87d3-4b938e123493