Skip to content

test(webapp): cover decentralized browser training across browsers - #1239

Open
ale18V wants to merge 7 commits into
mainfrom
test/browser-browser-cypress-ci
Open

ale18V wants to merge 7 commits into
mainfrom
test/browser-browser-cypress-ci

Conversation

@ale18V

@ale18V ale18V commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

What & why

Adds end-to-end webapp coverage for decentralized browser-to-browser training, as requested in #1196 and the review of #1230. Four real browser participants (two Chrome and two Firefox) train the default MNIST task through the webapp against a live Disco server over WebRTC. The run exercises Chrome–Chrome, Firefox–Firefox, and Chrome–Firefox model exchange.

Technical plan

Keep the test with the other webapp training suites. Start the standard built Disco server and a Vite webapp, then run four Cypress browser processes on a shared Xvfb display in CI. Assert that all participants complete 20 epochs and 10 model-sharing rounds.

Deviations from plan

None. This replaces the Node participant prototype in #1232 with browser-to-browser collaboration.

Todo

None.

@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch from 55697bc to e489b7f Compare October 2, 2026 09:51
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch from e489b7f to 0e054da Compare October 2, 2026 12:33
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch from 0e054da to e76d17c Compare October 3, 2026 11:17
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch from e76d17c to a7b402f Compare October 3, 2026 11:20
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch 2 times, most recently from ee165f3 to f335779 Compare October 5, 2026 21:57
@ale18V
ale18V changed the base branch from test/decentralized-webapp-ci to main October 5, 2026 21:57
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch from f335779 to f6cc2e0 Compare October 6, 2026 07:12
@ale18V ale18V changed the title test(webapp): probe Chrome–Firefox decentralized training test(webapp): cover decentralized browser training across browsers Oct 6, 2026
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch 2 times, most recently from 0112c7a to 6da8cc1 Compare October 10, 2026 13:59
@ale18V
ale18V marked this pull request as ready for review October 10, 2026 14:01
@ale18V
ale18V requested a review from JulienVig October 10, 2026 14:13
@ale18V

ale18V commented Oct 10, 2026

Copy link
Copy Markdown
Collaborator Author

I've also refactored the support folder to have a dedicated support/training folder

@ale18V
ale18V added this pull request to stack #1257 October 11, 2026 10:39
@ale18V
ale18V force-pushed the test/browser-browser-cypress-ci branch from be145af to bdc2a99 Compare October 12, 2026 12:25

@JulienVig JulienVig left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the great work! I mostly have nitpicking comments but I'm requesting changes because the CI is currently flaky. I just merged #1259 which should fix the error. You can request the review again once you rebased and see that the CI passes consistently

const browsers = process.env.DISCO_E2E_BROWSERS?.split(",") ?? [
"chrome",
"chrome",
"firefox",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"firefox",
"edge",

Could you swap one of the firefoxes by edge? I realized that in a hospital use case, most people would probably use the default microsoft browser. Since it's chromium based it shouldn't change much but let's include since it doesn't cost anything

import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process";
import { createInterface } from "node:readline";

const browsers = process.env.DISCO_E2E_BROWSERS?.split(",") ?? [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is DISCO_E2E_BROWSERS ever used? If not let's remove it and we can add it back when we actually need it. Otherwise can you document it?

Also this split is error prone if whitespaces are used for ex: "chrome, firefox", I think it should fail loudly if the env contains whitespace

process.exitCode = 1;
});

const results = browsers.map((browser, index) => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 4 browsers are started sequentially but MNIST by default only waits for 3 peers to start aggregation, this can leave the last browser hanging. This is maybe the reason why the CI failed for your other PR.
You could overwrite the min number of participants for MNIST to 4

for (const child of children) {
if (child.pid === undefined || child.exitCode !== null) continue;
try {
process.kill(-child.pid, "SIGTERM");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
process.kill(-child.pid, "SIGTERM");
process.kill(-child.pid, "SIGTERM"); // minus sign means kill both cypress and its browser

cy.contains("button", "Start training").click();
assertNoErrorToast();

const expectedParticipants = Cypress.env("numberOfParticipants") ?? 4;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cypress.env is deprecated. Use cy.env or Cypress.expose instead

cy.contains("button", "group").click();
cy.task<string[]>("readdir", "../datasets/CIFAR10").then((files) =>
cy
.contains("h4", "Group label: 0")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.contains("h4", "Group label: 0")
.contains("h4", "Group label: 0") // dummy labels for now

Comment on lines +9 to +14
cy.visit("/");
cy.contains("a", "Start training").click();
cy.get(".driver-popover-close-btn").click();
cy.get("#mnist", { timeout: 30_000 })
.contains("button", "participate")
.click();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could extend goToTaskOverview to accept an optional task ID and go to task if specified

Comment on lines +39 to +42
cy.contains("h6", "Collaborative model sharing")
.next({ timeout: 270_000 })
.should("have.text", "10");
cy.contains("Training successfully completed", { timeout: 270_000 });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cy.contains("h6", "Collaborative model sharing")
.next({ timeout: 270_000 })
.should("have.text", "10");
cy.contains("Training successfully completed", { timeout: 270_000 });
cy.contains("h6", "Collaborative model sharing")
.next()
.should("have.text", "10");
cy.contains("Training successfully completed");

I think that once we reached epoch 20 there's no need to add such long timeouts

const expectedParticipants = Cypress.env("numberOfParticipants") ?? 4;

cy.contains("h6", "number of participants")
.next({ timeout: 270_000 })

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need to wait that long before the 3 participants are connected?

Comment on lines +73 to +78
child.once("exit", (code, signal) => {
const passed = code === 0;
if (!passed) {
console.error(`[${label}] exited with ${code ?? signal}`);
stopChildren();
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you save and print which browser failed first? (For example by saving the label in variable that you only set if undefined). This would be helpful for understanding what went wrong

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants