Skip to content

Commit 7f14753

Browse files
authored
Enable Pyodide input test (#1125)
Closes RaspberryPiFoundation/digital-editor-issues#327 Changes where also ensure the pyodide execution in Cypress is closer aligned to how it's used
1 parent 2aa21e3 commit 7f14753

18 files changed

+444
-208
lines changed

.github/workflows/ci-cd.yml

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ jobs:
9595
yarn start
9696
wait-on: "http://localhost:3011"
9797
quiet: true
98+
config-file: cypress.config.mjs
99+
browser: chrome
98100
env:
99101
REACT_APP_API_ENDPOINT: "https://test-editor-api.raspberrypi.org"
100102
PUBLIC_URL: "http://localhost:3011"

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3333

3434
### Fixed
3535

36+
- Fixed pyodide input test and cypress config to enable further pyodide tests (#1125)
3637
- Image sizing and wrapping in the sidebar (#1126)
3738

3839
## [0.28.4] - 2024-10-23

cypress.config.mjs

+8
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ export default defineConfig({
1717
return null;
1818
},
1919
});
20+
on("before:browser:launch", (browser = {}, launchOptions) => {
21+
if (browser.name === "chrome") {
22+
console.log("Applying Chrome launch options");
23+
launchOptions.args.push("--enable-features=SharedArrayBuffer");
24+
launchOptions.args.push("--disable-site-isolation-trials");
25+
}
26+
return launchOptions;
27+
});
2028
},
2129
retries: {
2230
runMode: 3,

cypress/e2e/missionZero-wc.cy.js

+15-7
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,23 @@ it("picks up calls to input()", () => {
137137
cy.get("editor-wc")
138138
.shadow()
139139
.find("div[class=cm-content]")
140-
.invoke("text", "input()");
140+
.invoke("text", "name = input('What is your name?')\nprint('Hello', name)");
141141
cy.get("editor-wc").shadow().find(".btn--run").click();
142+
cy.get("editor-wc").shadow().find(".btn--stop").should("be.visible");
142143
cy.get("editor-wc")
143144
.shadow()
144-
.find(
145-
"div[class='pythonrunner-container skulptrunner skulptrunner--active']",
146-
)
147-
.contains("Text output")
145+
.find("div.pythonrunner-container.skulptrunner.skulptrunner--active")
146+
.contains(".react-tabs__tab-text", "Text output")
148147
.click();
149148
cy.get("editor-wc")
150149
.shadow()
151150
.find("span[contenteditable=true]")
152-
.type("{enter}");
151+
.type("Scott{enter}");
153152
cy.get("#results").should("contain", '"noInputEvents":false');
153+
cy.get("editor-wc")
154+
.shadow()
155+
.find(".pythonrunner-console-output-line")
156+
.should("contain", "Hello Scott");
154157
});
155158

156159
it("picks up calls to wait for motion", () => {
@@ -208,7 +211,12 @@ it("returns duration of null if focus is lost", () => {
208211
"text",
209212
'from sense_hat import SenseHat\nsense = SenseHat()\nsense.show_message("a")',
210213
);
211-
cy.get("editor-wc").shadow().find(".btn--run").click();
214+
cy.get("editor-wc")
215+
.shadow()
216+
.find(".btn--run")
217+
.should("not.be.disabled")
218+
.click();
219+
cy.get("editor-wc").shadow().find(".btn--stop").should("be.visible");
212220
cy.window().blur();
213221
cy.window().focus();
214222
cy.get("#results").should("contain", '"duration":null');

cypress/e2e/spec-wc-pyodide.cy.js

+66-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ const origin = "http://localhost:3011/web-component.html";
33
beforeEach(() => {
44
cy.intercept("*", (req) => {
55
req.headers["Origin"] = origin;
6-
req.continue();
76
});
87
});
98

@@ -13,12 +12,22 @@ const runCode = (code) => {
1312
.shadow()
1413
.find("div[class=cm-content]")
1514
.invoke("text", `${code}\n`);
16-
cy.get("editor-wc").shadow().find(".btn--run").click();
15+
cy.get("editor-wc")
16+
.shadow()
17+
.find(".btn--run")
18+
.should("not.be.disabled")
19+
.click();
1720
};
1821

1922
describe("Running the code with pyodide", () => {
2023
beforeEach(() => {
21-
cy.visit(origin);
24+
cy.visit({
25+
url: origin,
26+
headers: {
27+
"Cross-Origin-Opener-Policy": "same-origin",
28+
"Cross-Origin-Embedder-Policy": "require-corp",
29+
},
30+
});
2231
cy.window().then((win) => {
2332
Object.defineProperty(win, "crossOriginIsolated", {
2433
value: true,
@@ -29,6 +38,16 @@ describe("Running the code with pyodide", () => {
2938

3039
it("runs a simple program", () => {
3140
runCode('print("Hello world")');
41+
cy.get("editor-wc")
42+
.shadow()
43+
.find(".pyodiderunner")
44+
.contains(".react-tabs__tab", "Visual output")
45+
.should("not.exist");
46+
cy.get("editor-wc")
47+
.shadow()
48+
.find(".pyodiderunner")
49+
.find(".react-tabs__tab--selected")
50+
.should("contain", "Text output");
3251
cy.get("editor-wc")
3352
.shadow()
3453
.find(".pythonrunner-console-output-line")
@@ -39,21 +58,33 @@ describe("Running the code with pyodide", () => {
3958
runCode(
4059
"from time import sleep\nfor i in range(100):\n\tprint(i)\n\tsleep(1)",
4160
);
42-
cy.get("editor-wc").shadow().find(".btn--stop").click();
61+
cy.get("editor-wc")
62+
.shadow()
63+
.find(".pythonrunner-console-output-line")
64+
.should("contain", "3");
65+
cy.get("editor-wc")
66+
.shadow()
67+
.find(".btn--stop")
68+
.should("be.visible")
69+
.click();
4370
cy.get("editor-wc")
4471
.shadow()
4572
.find(".error-message__content")
4673
.should("contain", "Execution interrupted");
4774
});
4875

49-
// skip this test for now until we get the headers set up
50-
it.skip("runs a simple program with an input", () => {
76+
it("runs a simple program with an input", () => {
5177
runCode('name = input("What is your name?")\nprint("Hello", name)');
78+
cy.get("editor-wc").shadow().find(".btn--stop").should("be.visible");
5279
cy.get("editor-wc")
5380
.shadow()
5481
.find(".pythonrunner-console-output-line")
5582
.should("contain", "What is your name?");
56-
cy.get("editor-wc").shadow().find("#input").invoke("text", "Lois{enter}");
83+
cy.get("editor-wc")
84+
.shadow()
85+
.find("#input")
86+
.should("be.visible")
87+
.type("Lois{enter}");
5788
cy.get("editor-wc")
5889
.shadow()
5990
.find(".pythonrunner-console-output-line")
@@ -133,6 +164,34 @@ describe("Running the code with pyodide", () => {
133164
.should("contain", "4");
134165
});
135166

167+
it("runs a simple program with the py-enigma library", () => {
168+
runCode(
169+
`
170+
from enigma.machine import EnigmaMachine
171+
# Sheet settings
172+
ROTORS = "IV I V"
173+
RINGS = "20 5 10"
174+
PLUGBOARD = "KT AJ IV US NY HL GD XF PB CQ"
175+
def use_enigma_machine(msg, rotor_start):
176+
# Set up the Enigma machine
177+
machine = EnigmaMachine.from_key_sheet(rotors=ROTORS, reflector="B", ring_settings=RINGS, plugboard_settings=PLUGBOARD)
178+
# Set the initial position of the rotors
179+
machine.set_display(rotor_start)
180+
# Encrypt or decrypt the message
181+
transformed_msg = machine.process_text(msg)
182+
return(transformed_msg)
183+
text_in = "This is a test message"
184+
rotor_start = "FNZ"
185+
text_out = use_enigma_machine(text_in, rotor_start)
186+
print(text_out)
187+
`,
188+
);
189+
cy.get("editor-wc")
190+
.shadow()
191+
.find(".pythonrunner-console-output-line")
192+
.should("contain", "ULRYQJMVHLFQKBEFUGEOFL");
193+
});
194+
136195
it("errors when importing a non-existent module", () => {
137196
runCode("import i_do_not_exist");
138197
cy.get("editor-wc")

cypress/e2e/spec-wc-skulpt.cy.js

+33-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ const runCode = (code) => {
1414
.find("div[class=cm-content]")
1515
.invoke("text", `${code}\n`);
1616
cy.wait(200);
17-
cy.get("editor-wc").shadow().find(".btn--run").click();
17+
cy.get("editor-wc")
18+
.shadow()
19+
.find(".btn--run")
20+
.should("not.be.disabled")
21+
.click();
1822
};
1923

2024
describe("Running the code with skulpt", () => {
@@ -28,10 +32,38 @@ describe("Running the code with skulpt", () => {
2832
});
2933
});
3034

35+
it("runs a simple program", () => {
36+
runCode("print('Hello world')");
37+
cy.get("editor-wc")
38+
.shadow()
39+
.find(".skulptrunner")
40+
.contains(".react-tabs__tab", "Visual output")
41+
.should("not.exist");
42+
cy.get("editor-wc")
43+
.shadow()
44+
.find(".skulptrunner")
45+
.find(".react-tabs__tab--selected")
46+
.should("contain", "Text output");
47+
cy.get("editor-wc")
48+
.shadow()
49+
.find(".pythonrunner-console-output-line")
50+
.should("contain", "Hello world");
51+
});
52+
3153
it("runs a simple p5 program", () => {
3254
runCode(
3355
"from p5 import *\n\ndef setup():\n\tsize(400, 400)\ndef draw():\n\tfill('cyan')\n\trect(0, 0, 400, 250)\nrun(frame_rate=2)",
3456
);
57+
cy.get("editor-wc")
58+
.shadow()
59+
.find(".skulptrunner")
60+
.contains(".react-tabs__tab", "Text output")
61+
.should("exist");
62+
cy.get("editor-wc")
63+
.shadow()
64+
.find(".skulptrunner")
65+
.find(".react-tabs__tab--selected")
66+
.should("contain", "Visual output");
3567
cy.get("editor-wc").shadow().find(".p5Canvas").should("exist");
3668
});
3769

cypress/e2e/spec-wc.cy.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,18 @@ describe("when embedded, output_only & output_split_view are true", () => {
113113

114114
// Check text output panel is visible and has a run button
115115
// Important to wait for this before making the negative assertions that follow
116-
cy.get("editor-wc").shadow().contains("Text output").should("be.visible");
116+
const runnerContainer = cy
117+
.get("editor-wc")
118+
.shadow()
119+
.find(".proj-runner-container");
120+
runnerContainer
121+
.find(".react-tabs__tab--selected")
122+
.should("contain", "Text output");
117123
cy.get("editor-wc")
118124
.shadow()
119125
.find("button")
120126
.contains("Run")
127+
.should("not.be.disabled")
121128
.should("be.visible");
122129

123130
// Check that the side bar is not displayed
@@ -160,6 +167,7 @@ describe("when embedded, output_only & output_split_view are true", () => {
160167
.shadow()
161168
.find("button")
162169
.contains("Run")
170+
.should("not.be.disabled")
163171
.should("be.visible");
164172

165173
// Check that the code has automatically run i.e. the HTML has been rendered

src/assets/stylesheets/PythonRunner.scss

+16
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,22 @@
5555
position: relative;
5656
}
5757

58+
.pyodiderunner {
59+
display: none;
60+
61+
&--active {
62+
display: flex;
63+
}
64+
}
65+
66+
.skulptrunner {
67+
display: none;
68+
69+
&--active {
70+
display: flex;
71+
}
72+
}
73+
5874
.visual-output {
5975
flex: 1;
6076
display: flex;

src/components/Editor/Runners/HtmlRunner/HtmlRunner.jsx

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
showErrorModal,
1212
codeRunHandled,
1313
triggerCodeRun,
14+
loadingRunner,
15+
setLoadedRunner,
1416
} from "../../../../redux/EditorSlice";
1517

1618
import {
@@ -166,6 +168,8 @@ function HtmlRunner() {
166168

167169
useEffect(() => {
168170
eventListener();
171+
dispatch(loadingRunner("html"));
172+
dispatch(setLoadedRunner("html"));
169173
}, []);
170174

171175
let timeout;

0 commit comments

Comments
 (0)