Skip to content

Commit bbdfad8

Browse files
authored
Fix skulpt support for output panels attribute (#1158)
1 parent 8204181 commit bbdfad8

File tree

4 files changed

+150
-97
lines changed

4 files changed

+150
-97
lines changed

CHANGELOG.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## Unreleased
8+
9+
## [0.28.14] - 2025-01-06
10+
11+
### Fixed
12+
13+
- Support for the `outputPanels` attribute in the `SkulptRunner` (#1158)
14+
715
## [0.28.13] - 2024-12-18
816

917
### Changed
@@ -1019,7 +1027,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
10191027

10201028
- Events in Web Component indicating whether Mission Zero criteria have been met (#113)
10211029

1022-
[unreleased]: https://github.com/RaspberryPiFoundation/editor-ui/compare/v0.28.13...HEAD
1030+
[unreleased]: https://github.com/RaspberryPiFoundation/editor-ui/compare/v0.28.14...HEAD
1031+
[0.28.14]: https://github.com/RaspberryPiFoundation/editor-ui/releases/tag/v0.28.14
10231032
[0.28.13]: https://github.com/RaspberryPiFoundation/editor-ui/releases/tag/v0.28.13
10241033
[0.28.12]: https://github.com/RaspberryPiFoundation/editor-ui/releases/tag/v0.28.12
10251034
[0.28.11]: https://github.com/RaspberryPiFoundation/editor-ui/releases/tag/v0.28.11

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@raspberrypifoundation/editor-ui",
3-
"version": "0.28.13",
3+
"version": "0.28.14",
44
"private": true,
55
"dependencies": {
66
"@apollo/client": "^3.7.8",

src/components/Editor/Runners/PythonRunner/PythonRunner.jsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const SKULPT_ONLY_MODULES = [
1515
"turtle",
1616
];
1717

18-
const PythonRunner = () => {
18+
const PythonRunner = ({ outputPanels = ["text", "visual"] }) => {
1919
const dispatch = useDispatch();
2020

2121
const project = useSelector((state) => state.editor.project);
@@ -93,7 +93,10 @@ const PythonRunner = () => {
9393
return (
9494
<>
9595
<PyodideRunner active={activeRunner === "pyodide"} />
96-
<SkulptRunner active={activeRunner === "skulpt"} />
96+
<SkulptRunner
97+
active={activeRunner === "skulpt"}
98+
outputPanels={outputPanels}
99+
/>
97100
</>
98101
);
99102
};
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render } from "@testing-library/react";
1+
import { render, within } from "@testing-library/react";
22
import { Provider } from "react-redux";
33
import { act } from "react-dom/test-utils";
44
import PythonRunner from "./PythonRunner";
@@ -56,110 +56,151 @@ const updateRunner = ({
5656
store.dispatch(setSenseHatAlwaysEnabled(senseHatAlwaysEnabled));
5757
});
5858
};
59+
describe("PythonRunner with default props", () => {
60+
beforeEach(() => {
61+
window.crossOriginIsolated = true;
62+
render(
63+
<Provider store={store}>
64+
<PythonRunner />
65+
</Provider>,
66+
);
67+
updateRunner({ code: "print('some loaded code')" });
68+
});
5969

60-
beforeEach(() => {
61-
window.crossOriginIsolated = true;
62-
render(
63-
<Provider store={store}>
64-
<PythonRunner />
65-
</Provider>,
66-
);
67-
updateRunner({ code: "print('some loaded code')" });
68-
});
70+
test("Renders with Pyodide runner initially", () => {
71+
updateRunner({});
72+
expect(
73+
document.querySelector(".skulptrunner--active"),
74+
).not.toBeInTheDocument();
75+
expect(
76+
document.querySelector(".pyodiderunner--active"),
77+
).toBeInTheDocument();
78+
});
6979

70-
test("Renders with Pyodide runner initially", () => {
71-
updateRunner({});
72-
expect(
73-
document.querySelector(".skulptrunner--active"),
74-
).not.toBeInTheDocument();
75-
expect(document.querySelector(".pyodiderunner--active")).toBeInTheDocument();
76-
});
80+
test("Uses pyodide when no skulpt-only modules are imported", () => {
81+
updateRunner({ code: "import math" });
82+
expect(
83+
document.querySelector(".skulptrunner--active"),
84+
).not.toBeInTheDocument();
85+
expect(
86+
document.querySelector(".pyodiderunner--active"),
87+
).toBeInTheDocument();
88+
});
7789

78-
test("Uses pyodide when no skulpt-only modules are imported", () => {
79-
updateRunner({ code: "import math" });
80-
expect(
81-
document.querySelector(".skulptrunner--active"),
82-
).not.toBeInTheDocument();
83-
expect(document.querySelector(".pyodiderunner--active")).toBeInTheDocument();
84-
});
90+
test("Uses skulpt when skulpt-only modules are imported", () => {
91+
updateRunner({ code: "import p5" });
92+
expect(
93+
document.querySelector(".pyodiderunner--active"),
94+
).not.toBeInTheDocument();
95+
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
96+
});
8597

86-
test("Uses skulpt when skulpt-only modules are imported", () => {
87-
updateRunner({ code: "import p5" });
88-
expect(
89-
document.querySelector(".pyodiderunner--active"),
90-
).not.toBeInTheDocument();
91-
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
92-
});
98+
test("Uses skulpt when senseHatAlwaysEnabled is true", () => {
99+
updateRunner({ code: "import math", senseHatAlwaysEnabled: true });
100+
expect(
101+
document.querySelector(".pyodiderunner--active"),
102+
).not.toBeInTheDocument();
103+
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
104+
});
93105

94-
test("Uses skulpt when senseHatAlwaysEnabled is true", () => {
95-
updateRunner({ code: "import math", senseHatAlwaysEnabled: true });
96-
expect(
97-
document.querySelector(".pyodiderunner--active"),
98-
).not.toBeInTheDocument();
99-
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
100-
});
106+
test("Uses skulpt if not cross origin isolated", () => {
107+
window.crossOriginIsolated = false;
108+
updateRunner({ code: "import math" });
109+
expect(
110+
document.querySelector(".pyodiderunner--active"),
111+
).not.toBeInTheDocument();
112+
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
113+
});
101114

102-
test("Uses skulpt if not cross origin isolated", () => {
103-
window.crossOriginIsolated = false;
104-
updateRunner({ code: "import math" });
105-
expect(
106-
document.querySelector(".pyodiderunner--active"),
107-
).not.toBeInTheDocument();
108-
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
109-
});
115+
test("Switches runners if the import has a from clause", () => {
116+
updateRunner({ code: "from p5 import *" });
117+
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
118+
expect(
119+
document.querySelector(".pyodiderunner--active"),
120+
).not.toBeInTheDocument();
121+
});
110122

111-
test("Switches runners if the import has a from clause", () => {
112-
updateRunner({ code: "from p5 import *" });
113-
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
114-
expect(
115-
document.querySelector(".pyodiderunner--active"),
116-
).not.toBeInTheDocument();
117-
});
123+
test("Switches runners if the import is indented", () => {
124+
updateRunner({ code: " import p5" });
125+
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
126+
expect(
127+
document.querySelector(".pyodiderunner--active"),
128+
).not.toBeInTheDocument();
129+
});
118130

119-
test("Switches runners if the import is indented", () => {
120-
updateRunner({ code: " import p5" });
121-
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
122-
expect(
123-
document.querySelector(".pyodiderunner--active"),
124-
).not.toBeInTheDocument();
125-
});
131+
test("Uses skulpt if the py5 magic comment is used", () => {
132+
updateRunner({ code: "# input.comment.py5" });
133+
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
134+
expect(
135+
document.querySelector(".pyodiderunner--active"),
136+
).not.toBeInTheDocument();
137+
});
126138

127-
test("Uses skulpt if the py5 magic comment is used", () => {
128-
updateRunner({ code: "# input.comment.py5" });
129-
expect(document.querySelector(".skulptrunner--active")).toBeInTheDocument();
130-
expect(
131-
document.querySelector(".pyodiderunner--active"),
132-
).not.toBeInTheDocument();
133-
});
139+
test("Does not switch runners while the code is running", () => {
140+
updateRunner({ code: "import p5", codeRunTriggered: true });
141+
expect(
142+
document.querySelector(".pyodiderunner--active"),
143+
).toBeInTheDocument();
144+
expect(
145+
document.querySelector(".skulptrunner--active"),
146+
).not.toBeInTheDocument();
147+
});
134148

135-
test("Does not switch runners while the code is running", () => {
136-
updateRunner({ code: "import p5", codeRunTriggered: true });
137-
expect(document.querySelector(".pyodiderunner--active")).toBeInTheDocument();
138-
expect(
139-
document.querySelector(".skulptrunner--active"),
140-
).not.toBeInTheDocument();
141-
});
149+
test("Does not switch runners if the import is in a comment", () => {
150+
updateRunner({ code: "# import p5" });
151+
expect(
152+
document.querySelector(".pyodiderunner--active"),
153+
).toBeInTheDocument();
154+
expect(
155+
document.querySelector(".skulptrunner--active"),
156+
).not.toBeInTheDocument();
157+
});
142158

143-
test("Does not switch runners if the import is in a comment", () => {
144-
updateRunner({ code: "# import p5" });
145-
expect(document.querySelector(".pyodiderunner--active")).toBeInTheDocument();
146-
expect(
147-
document.querySelector(".skulptrunner--active"),
148-
).not.toBeInTheDocument();
149-
});
159+
test("Does not switch runners if the import is in a string", () => {
160+
updateRunner({ code: 'print("import p5")' });
161+
expect(
162+
document.querySelector(".pyodiderunner--active"),
163+
).toBeInTheDocument();
164+
expect(
165+
document.querySelector(".skulptrunner--active"),
166+
).not.toBeInTheDocument();
167+
});
150168

151-
test("Does not switch runners if the import is in a string", () => {
152-
updateRunner({ code: 'print("import p5")' });
153-
expect(document.querySelector(".pyodiderunner--active")).toBeInTheDocument();
154-
expect(
155-
document.querySelector(".skulptrunner--active"),
156-
).not.toBeInTheDocument();
169+
test("Does not switch runners if the import is in a multiline string", () => {
170+
updateRunner({ code: '"""\nimport p5\n"""' });
171+
expect(
172+
document.querySelector(".pyodiderunner--active"),
173+
).toBeInTheDocument();
174+
expect(
175+
document.querySelector(".skulptrunner--active"),
176+
).not.toBeInTheDocument();
177+
});
178+
179+
test("Renders the text output in the skulpt runner", () => {
180+
updateRunner({ code: "import p5" });
181+
const skulptRunner = document.querySelector(".skulptrunner");
182+
expect(
183+
within(skulptRunner).queryByText("output.textOutput"),
184+
).toBeInTheDocument();
185+
});
157186
});
158187

159-
test("Does not switch runners if the import is in a multiline string", () => {
160-
updateRunner({ code: '"""\nimport p5\n"""' });
161-
expect(document.querySelector(".pyodiderunner--active")).toBeInTheDocument();
162-
expect(
163-
document.querySelector(".skulptrunner--active"),
164-
).not.toBeInTheDocument();
188+
describe("PythonRunner with output panels set to visual only", () => {
189+
beforeEach(() => {
190+
window.crossOriginIsolated = true;
191+
render(
192+
<Provider store={store}>
193+
<PythonRunner outputPanels={["visual"]} />
194+
</Provider>,
195+
);
196+
updateRunner({ code: "print('some loaded code')" });
197+
});
198+
199+
test("Does not render text output in the skulpt runner", () => {
200+
updateRunner({ code: "import p5" });
201+
const skulptRunner = document.querySelector(".skulptrunner");
202+
expect(
203+
within(skulptRunner).queryByText("output.textOutput"),
204+
).not.toBeInTheDocument();
205+
});
165206
});

0 commit comments

Comments
 (0)