From d8ebed345d4029a39459bb14b8fd02b4d525db10 Mon Sep 17 00:00:00 2001 From: Chris Zetter <253059100+zetter-rpf@users.noreply.github.com> Date: Fri, 9 Jan 2026 16:44:00 +0000 Subject: [PATCH 1/3] Introduce testing library for cypress We're already using @testing-library for our react code, the library for cypress brings the same benefits - it will allow us to write end to end tests that better mimic user behaviour by interacting with elements based on their role/text/labels rather than their classes. As well as making the specs easier to follow and de-coupled from our class names, it helps to ensure our site is accessible (i.e form elements have labels). To demonstrate this I've written added a new test to work with multiple files. If we like this approach, we can change over other specs as we write or update them. Note that cypress testing library doesn't seem to have direct support for the Shadow DOM yet (see https://github.com/testing-library/dom-testing-library/issues/413 ) but we still works if we load the shadow DOM using the cypress finder. One quirk I found is that `findByLabelText` doesn't work from the root shadow dom element which is why I've called it on `children()`. --- cypress.config.mjs | 1 - cypress/e2e/spec-wc-pyodide.cy.js | 39 ++++++++++++++++++ cypress/support/e2e.js | 1 + package.json | 1 + yarn.lock | 66 +++++++++++++++++++++++++++---- 5 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 cypress/support/e2e.js diff --git a/cypress.config.mjs b/cypress.config.mjs index bab13a195..d7f5df804 100644 --- a/cypress.config.mjs +++ b/cypress.config.mjs @@ -6,7 +6,6 @@ dotenv.config(); export default defineConfig({ e2e: { chromeWebSecurity: false, - supportFile: false, defaultCommandTimeout: 10000, video: false, defaultBrowser: "chrome", diff --git a/cypress/e2e/spec-wc-pyodide.cy.js b/cypress/e2e/spec-wc-pyodide.cy.js index 24bd6fc74..d95764eff 100644 --- a/cypress/e2e/spec-wc-pyodide.cy.js +++ b/cypress/e2e/spec-wc-pyodide.cy.js @@ -151,6 +151,45 @@ describe("Running the code with pyodide", () => { .should("contain", "3"); }); + it("runs a program with muiltiple files", () => { + cy.get("editor-wc") + .shadow() + .findByLabelText('editor text input') + .invoke("text", `from my_number import NUMBER\nprint(NUMBER)\n`); + + cy.get("editor-wc") + .shadow() + .findByRole('button', { name: 'Add file' }).click() + + cy.get("editor-wc") + .shadow() + .children() + .findByLabelText(/Name your file/) + .type("my_number.py"); + + cy.get("editor-wc") + .shadow() + .findByRole('dialog') + .findByRole('button', { name: 'Add file' }).click() + + cy.get("editor-wc") + .shadow() + .findByLabelText('editor text input') + .invoke("text", `NUMBER = 42\n`); + + cy.get("editor-wc") + .shadow() + .findByRole('button', { name: 'Run' }).click() + + cy.get("editor-wc") + .shadow() + .children() + .find(".pyodiderunner") + .findByLabelText('Text output') + .should("contain", "42"); + }); + + it("runs a simple program with a built-in pyodide module", () => { runCode( "import simplejson as json\nprint(json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]))", diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js new file mode 100644 index 000000000..56e9d27b7 --- /dev/null +++ b/cypress/support/e2e.js @@ -0,0 +1 @@ +import '@testing-library/cypress/add-commands' \ No newline at end of file diff --git a/package.json b/package.json index 9609b6621..81701a642 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,7 @@ "@pmmmwh/react-refresh-webpack-plugin": "0.4.3", "@react-three/test-renderer": "8.2.1", "@svgr/webpack": "5.5.0", + "@testing-library/cypress": "^10.1.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "14.3.1", "@testing-library/user-event": "^12.1.10", diff --git a/yarn.lock b/yarn.lock index 644a9c9c5..0167075a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1620,6 +1620,13 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.14.6": + version: 7.28.4 + resolution: "@babel/runtime@npm:7.28.4" + checksum: 934b0a0460f7d06637d93fcd1a44ac49adc33518d17253b5a0b55ff4cb90a45d8fe78bf034b448911dbec7aff2a90b918697559f78d21c99ff8dbadae9565b55 + languageName: node + linkType: hard + "@babel/template@npm:^7.25.7, @babel/template@npm:^7.3.3": version: 7.25.7 resolution: "@babel/template@npm:7.25.7" @@ -2966,6 +2973,7 @@ __metadata: "@sentry/tracing": 7.16.0 "@svgr/webpack": 5.5.0 "@szhsin/react-menu": ^3.2.0 + "@testing-library/cypress": ^10.1.0 "@testing-library/jest-dom": ^5.16.5 "@testing-library/react": 14.3.1 "@testing-library/user-event": ^12.1.10 @@ -3707,6 +3715,34 @@ __metadata: languageName: node linkType: hard +"@testing-library/cypress@npm:^10.1.0": + version: 10.1.0 + resolution: "@testing-library/cypress@npm:10.1.0" + dependencies: + "@babel/runtime": ^7.14.6 + "@testing-library/dom": ^10.1.0 + peerDependencies: + cypress: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 + checksum: 0a5a433fff11c35244d87f2a1d5974d5ef4478212a94245062b4dce5459bc367b26faa9f436cf11f2cb956927658b9849506735a93f64247fffc8690fc603fcb + languageName: node + linkType: hard + +"@testing-library/dom@npm:^10.1.0": + version: 10.4.1 + resolution: "@testing-library/dom@npm:10.4.1" + dependencies: + "@babel/code-frame": ^7.10.4 + "@babel/runtime": ^7.12.5 + "@types/aria-query": ^5.0.1 + aria-query: 5.3.0 + dom-accessibility-api: ^0.5.9 + lz-string: ^1.5.0 + picocolors: 1.1.1 + pretty-format: ^27.0.2 + checksum: 3887fe95594b6d9467a804e2cc82e719c57f4d55d7d9459b72a949b3a8189db40375b89034637326d4be559f115abc6b6bcfcc6fec0591c4a4d4cdde96751a6c + languageName: node + linkType: hard + "@testing-library/dom@npm:^9.0.0": version: 9.3.4 resolution: "@testing-library/dom@npm:9.3.4" @@ -5224,6 +5260,15 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:5.3.0": + version: 5.3.0 + resolution: "aria-query@npm:5.3.0" + dependencies: + dequal: ^2.0.3 + checksum: 305bd73c76756117b59aba121d08f413c7ff5e80fa1b98e217a3443fcddb9a232ee790e24e432b59ae7625aebcf4c47cb01c2cac872994f0b426f5bdfcd96ba9 + languageName: node + linkType: hard + "aria-query@npm:^5.0.0": version: 5.3.2 resolution: "aria-query@npm:5.3.2" @@ -8227,6 +8272,13 @@ __metadata: languageName: node linkType: hard +"dequal@npm:^2.0.3": + version: 2.0.3 + resolution: "dequal@npm:2.0.3" + checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90 + languageName: node + linkType: hard + "destroy@npm:1.2.0": version: 1.2.0 resolution: "destroy@npm:1.2.0" @@ -15500,6 +15552,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:1.1.1, picocolors@npm:^1.0.0, picocolors@npm:^1.1.0": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 + languageName: node + linkType: hard + "picocolors@npm:^0.2.1": version: 0.2.1 resolution: "picocolors@npm:0.2.1" @@ -15507,13 +15566,6 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.1.0": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 - languageName: node - linkType: hard - "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" From 1ac16fa66f15f7e79b1335f8037e63269912c653 Mon Sep 17 00:00:00 2001 From: Chris Zetter <253059100+zetter-rpf@users.noreply.github.com> Date: Fri, 9 Jan 2026 17:06:53 +0000 Subject: [PATCH 2/3] Use alias to reduce some of the repititon cypress aliases let you share values between setup and files. See [1] [1] https://docs.cypress.io/app/core-concepts/variables-and-aliases --- cypress/e2e/spec-wc-pyodide.cy.js | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/cypress/e2e/spec-wc-pyodide.cy.js b/cypress/e2e/spec-wc-pyodide.cy.js index d95764eff..9d228c003 100644 --- a/cypress/e2e/spec-wc-pyodide.cy.js +++ b/cypress/e2e/spec-wc-pyodide.cy.js @@ -34,6 +34,7 @@ describe("Running the code with pyodide", () => { configurable: true, }); }); + cy.get("editor-wc").shadow().children().as("editor"); }); it("runs a simple program", () => { @@ -152,38 +153,28 @@ describe("Running the code with pyodide", () => { }); it("runs a program with muiltiple files", () => { - cy.get("editor-wc") - .shadow() + cy.get("@editor") .findByLabelText('editor text input') .invoke("text", `from my_number import NUMBER\nprint(NUMBER)\n`); - cy.get("editor-wc") - .shadow() - .findByRole('button', { name: 'Add file' }).click() + cy.get("@editor").findByRole('button', { name: 'Add file' }).click() - cy.get("editor-wc") - .shadow() - .children() + cy.get("@editor") .findByLabelText(/Name your file/) .type("my_number.py"); - cy.get("editor-wc") - .shadow() + cy.get("@editor") .findByRole('dialog') .findByRole('button', { name: 'Add file' }).click() - cy.get("editor-wc") - .shadow() + cy.get("@editor") .findByLabelText('editor text input') .invoke("text", `NUMBER = 42\n`); - cy.get("editor-wc") - .shadow() - .findByRole('button', { name: 'Run' }).click() + cy.get("@editor") + .findByRole('button', { name: 'Run' }).click(); - cy.get("editor-wc") - .shadow() - .children() + cy.get("@editor") .find(".pyodiderunner") .findByLabelText('Text output') .should("contain", "42"); From 84f6ec8ffb38e46b2f6ad40b7759b43a65f9faa3 Mon Sep 17 00:00:00 2001 From: Chris Zetter <253059100+zetter-rpf@users.noreply.github.com> Date: Fri, 9 Jan 2026 17:08:53 +0000 Subject: [PATCH 3/3] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fd7f41df..3cf204c7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed +- Introduce @testing-library for cypress - Update cypress (#1283) ### Fixed