Skip to content

Commit fd604a8

Browse files
Update error message for ImportErrors (#1105)
## Closes: [#309](RaspberryPiFoundation/digital-editor-issues#309)
1 parent 38bb5c3 commit fd604a8

File tree

7 files changed

+3495
-3135
lines changed

7 files changed

+3495
-3135
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## Unreleased
88

9+
### Changed
10+
11+
- Updated the ImportErrors message
12+
- In ErrorMessage component added the way to display html elements in string
13+
914
### Added
1015

1116
- PyodideWorker setup for the editor (#1104)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ describe("Running the code with skulpt", () => {
134134
.find(".error-message__content")
135135
.should(
136136
"contain.text",
137-
"If you are using p5, py5, sense_hat or turtle, matplotlib might not work.",
137+
"ImportError: No module named matplotlib on line 2 of main.py. You should check your code for typos. If you are using p5, py5, sense_hat or turtle, matplotlib might not work - read this article for more information.",
138138
);
139139
});
140140
});

src/components/Editor/ErrorMessage/ErrorMessage.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import React, { useContext } from "react";
1+
import React, { useContext, useEffect, useRef } from "react";
22
import "../../../assets/stylesheets/ErrorMessage.scss";
33
import { useSelector } from "react-redux";
44
import { SettingsContext } from "../../../utils/settings";
55

66
const ErrorMessage = () => {
7+
const message = useRef();
78
const error = useSelector((state) => state.editor.error);
89
const settings = useContext(SettingsContext);
910

11+
useEffect(() => {
12+
if (message.current) {
13+
message.current.innerHTML = error;
14+
}
15+
}, [error]);
1016
return error ? (
1117
<div className={`error-message error-message--${settings.fontSize}`}>
12-
<pre className="error-message__content">{error}</pre>
18+
<pre ref={message} className="error-message__content"></pre>
1319
</div>
1420
) : null;
1521
};

src/components/Editor/ErrorMessage/ErrorMessage.test.js

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,42 @@ import ErrorMessage from "./ErrorMessage";
55
import { render, screen } from "@testing-library/react";
66

77
describe("When error is set", () => {
8-
beforeEach(() => {
9-
const middlewares = [];
10-
const mockStore = configureStore(middlewares);
8+
const middlewares = [];
9+
const mockStore = configureStore(middlewares);
10+
11+
describe("When error is set", () => {
12+
beforeEach(() => {
13+
const initialState = {
14+
editor: {
15+
error: "Oops",
16+
},
17+
};
18+
const store = mockStore(initialState);
19+
render(
20+
<Provider store={store}>
21+
<SettingsContext.Provider
22+
value={{ theme: "dark", fontSize: "myFontSize" }}
23+
>
24+
<ErrorMessage />
25+
</SettingsContext.Provider>
26+
</Provider>,
27+
);
28+
});
29+
30+
test("Error message displays", () => {
31+
expect(screen.queryByText("Oops")).toBeInTheDocument();
32+
});
33+
34+
test("Font size class is set correctly", () => {
35+
const errorMessage = screen.queryByText("Oops").parentElement;
36+
expect(errorMessage).toHaveClass("error-message--myFontSize");
37+
});
38+
});
39+
40+
it("should render links correctly within the error message", () => {
1141
const initialState = {
1242
editor: {
13-
error: "Oops",
43+
error: `ImportError: No module named pd on line 2 of main.py. You should check your code for typos. If you are using p5, py5, sense_hat or turtle, pd might not work - read this <a href=https://help.editor.raspberrypi.org/hc/en-us/articles/30841379339924-What-Python-libraries-are-available-in-the-Code-Editor>article</a> for more information.`,
1444
},
1545
};
1646
const store = mockStore(initialState);
@@ -23,14 +53,12 @@ describe("When error is set", () => {
2353
</SettingsContext.Provider>
2454
</Provider>,
2555
);
26-
});
27-
28-
test("Error message displays", () => {
29-
expect(screen.queryByText("Oops")).toBeInTheDocument();
30-
});
3156

32-
test("Font size class is set correctly", () => {
33-
const errorMessage = screen.queryByText("Oops").parentElement;
34-
expect(errorMessage).toHaveClass("error-message--myFontSize");
57+
const linkElement = screen.getByRole("link", { name: "article" });
58+
expect(linkElement).toBeInTheDocument();
59+
expect(linkElement).toHaveAttribute(
60+
"href",
61+
"https://help.editor.raspberrypi.org/hc/en-us/articles/30841379339924-What-Python-libraries-are-available-in-the-Code-Editor",
62+
);
3563
});
3664
});

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,9 @@ const SkulptRunner = ({ active, outputPanels = ["text", "visual"] }) => {
304304
const fileName = err.traceback[0].filename.replace(/^\.\//, "");
305305

306306
if (errorType === "ImportError" && window.crossOriginIsolated) {
307+
const articleLink = `https://help.editor.raspberrypi.org/hc/en-us/articles/30841379339924-What-Python-libraries-are-available-in-the-Code-Editor`;
307308
const moduleName = errorDescription.replace(/No module named /, "");
308-
explanation = `You should check your code for typos. If you are using p5, py5, sense_hat or turtle, ${moduleName} might not work.`;
309+
explanation = `You should check your code for typos. If you are using p5, py5, sense_hat or turtle, ${moduleName} might not work - read this <a href=${articleLink}>article</a> for more information.`;
309310
}
310311

311312
let userId;

src/components/Editor/Runners/PythonRunner/SkulptRunner/SkulptRunner.test.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ describe("When there is an import error and the site is cross-origin isolated",
283283
let store;
284284
beforeEach(() => {
285285
window.crossOriginIsolated = true;
286-
287286
const middlewares = [];
288287
const mockStore = configureStore(middlewares);
289288
const initialState = {
@@ -312,12 +311,10 @@ describe("When there is an import error and the site is cross-origin isolated",
312311
);
313312
});
314313
test("it shows the original error message and the explanation", () => {
315-
expect(store.getActions()).toEqual(
316-
expect.arrayContaining([
317-
setError(
318-
"ImportError: No module named fake_module on line 1 of main.py. You should check your code for typos. If you are using p5, py5, sense_hat or turtle, fake_module might not work.",
319-
),
320-
]),
314+
expect(store.getActions()).toContainEqual(
315+
setError(
316+
`ImportError: No module named fake_module on line 1 of main.py. You should check your code for typos. If you are using p5, py5, sense_hat or turtle, fake_module might not work - read this <a href=https://help.editor.raspberrypi.org/hc/en-us/articles/30841379339924-What-Python-libraries-are-available-in-the-Code-Editor>article</a> for more information.`,
317+
),
321318
);
322319
});
323320
});

0 commit comments

Comments
 (0)