Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive Sicp Bug Fixes #1812

Merged
merged 15 commits into from
Jun 21, 2021
Merged
36 changes: 36 additions & 0 deletions src/features/sicp/errors/SicpErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Component, ErrorInfo, ReactNode } from 'react';

import getSicpError, { SicpErrorType } from './SicpErrors';

type Props = {
children: ReactNode;
};

type State = {
hasError: boolean;
};

class SicpErrorBoundary extends Component<Props, State> {
public state: State = {
hasError: false
};

public static getDerivedStateFromError(_: Error): State {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}

public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Uncaught error:', error, errorInfo);
}

public render() {
if (this.state.hasError) {
return getSicpError(SicpErrorType.UNEXPECTED_ERROR);
}

return this.props.children;
}
}

export default SicpErrorBoundary;
58 changes: 58 additions & 0 deletions src/features/sicp/errors/SicpErrors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { NonIdealState } from '@blueprintjs/core';
import { IconNames } from '@blueprintjs/icons';

export enum SicpErrorType {
UNEXPECTED_ERROR,
PAGE_NOT_FOUND_ERROR,
PARSING_ERROR
}

const unexpectedError = (
<div>
Something unexpected went wrong trying to load this page. Please try refreshing the page. If the
issue persists, kindly let us know by filing an issue at{' '}
<a href="https://github.com/source-academy/cadet-frontend">
https://github.com/source-academy/cadet-frontend
</a>
.
</div>
);

const pageNotFoundError = (
<div>
We could not find the page you were looking for. Please check the URL again. If you believe the
URL is correct, kindly let us know by filing an issue at{' '}
<a href="https://github.com/source-academy/cadet-frontend">
https://github.com/source-academy/cadet-frontend
</a>
.
</div>
);

const parsingError = (
<div>
An error occured while loading the page. Kindly let us know by filing an issue at{' '}
<a href="https://github.com/source-academy/cadet-frontend">
https://github.com/source-academy/cadet-frontend
</a>{' '}
and we will get it fixed as soon as possible.
</div>
);

const errorComponent = (description: JSX.Element) => (
<NonIdealState title="Something went wrong :(" description={description} icon={IconNames.ERROR} />
);

const getSicpError = (type: SicpErrorType) => {
switch (type) {
case SicpErrorType.PAGE_NOT_FOUND_ERROR:
return errorComponent(pageNotFoundError);
case SicpErrorType.PARSING_ERROR:
return errorComponent(parsingError);
default:
// handle unexpected error case
return errorComponent(unexpectedError);
}
};

export default getSicpError;
20 changes: 20 additions & 0 deletions src/features/sicp/errors/__tests__/SicpErrors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { mount } from 'enzyme';

import getSicpError, { SicpErrorType } from '../SicpErrors';

describe('Sicp errors:', () => {
test('unexpected error renders correctly', () => {
const tree = mount(getSicpError(SicpErrorType.UNEXPECTED_ERROR));
expect(tree.debug()).toMatchSnapshot();
});

test('page not found error renders correctly', () => {
const tree = mount(getSicpError(SicpErrorType.PAGE_NOT_FOUND_ERROR));
expect(tree.debug()).toMatchSnapshot();
});

test('unexpected error renders correctly', () => {
const tree = mount(getSicpError(SicpErrorType.PARSING_ERROR));
expect(tree.debug()).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Sicp errors: page not found error renders correctly 1`] = `
"<Blueprint3.NonIdealState title=\\"Something went wrong :(\\" description={{...}} icon=\\"error\\">
<div className=\\"bp3-non-ideal-state\\">
<div className=\\"bp3-non-ideal-state-visual\\">
<Blueprint3.Icon icon=\\"error\\" iconSize={60}>
<span icon=\\"error\\" className=\\"bp3-icon bp3-icon-error\\" title={[undefined]}>
<svg fill={[undefined]} data-icon=\\"error\\" width={60} height={60} viewBox=\\"0 0 20 20\\">
<desc>
error
</desc>
<path d=\\"M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm1 16H9v-2h2v2zm0-3H9V4h2v9z\\" fillRule=\\"evenodd\\" />
</svg>
</span>
</Blueprint3.Icon>
</div>
<Component>
<h4 className=\\"bp3-heading\\">
Something went wrong :(
</h4>
</Component>
<div>
We could not find the page you were looking for. Please check the URL again. If you believe the URL is correct, kindly let us know by filing an issue at

<a href=\\"https://github.com/source-academy/cadet-frontend\\">
https://github.com/source-academy/cadet-frontend
</a>
.
</div>
</div>
</Blueprint3.NonIdealState>"
`;

exports[`Sicp errors: unexpected error renders correctly 1`] = `
"<Blueprint3.NonIdealState title=\\"Something went wrong :(\\" description={{...}} icon=\\"error\\">
<div className=\\"bp3-non-ideal-state\\">
<div className=\\"bp3-non-ideal-state-visual\\">
<Blueprint3.Icon icon=\\"error\\" iconSize={60}>
<span icon=\\"error\\" className=\\"bp3-icon bp3-icon-error\\" title={[undefined]}>
<svg fill={[undefined]} data-icon=\\"error\\" width={60} height={60} viewBox=\\"0 0 20 20\\">
<desc>
error
</desc>
<path d=\\"M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm1 16H9v-2h2v2zm0-3H9V4h2v9z\\" fillRule=\\"evenodd\\" />
</svg>
</span>
</Blueprint3.Icon>
</div>
<Component>
<h4 className=\\"bp3-heading\\">
Something went wrong :(
</h4>
</Component>
<div>
Something unexpected went wrong trying to load this page. Please try refreshing the page. If the issue persists, kindly let us know by filing an issue at

<a href=\\"https://github.com/source-academy/cadet-frontend\\">
https://github.com/source-academy/cadet-frontend
</a>
.
</div>
</div>
</Blueprint3.NonIdealState>"
`;

exports[`Sicp errors: unexpected error renders correctly 2`] = `
"<Blueprint3.NonIdealState title=\\"Something went wrong :(\\" description={{...}} icon=\\"error\\">
<div className=\\"bp3-non-ideal-state\\">
<div className=\\"bp3-non-ideal-state-visual\\">
<Blueprint3.Icon icon=\\"error\\" iconSize={60}>
<span icon=\\"error\\" className=\\"bp3-icon bp3-icon-error\\" title={[undefined]}>
<svg fill={[undefined]} data-icon=\\"error\\" width={60} height={60} viewBox=\\"0 0 20 20\\">
<desc>
error
</desc>
<path d=\\"M10 0C4.48 0 0 4.48 0 10s4.48 10 10 10 10-4.48 10-10S15.52 0 10 0zm1 16H9v-2h2v2zm0-3H9V4h2v9z\\" fillRule=\\"evenodd\\" />
</svg>
</span>
</Blueprint3.Icon>
</div>
<Component>
<h4 className=\\"bp3-heading\\">
Something went wrong :(
</h4>
</Component>
<div>
An error occured while loading the page. Kindly let us know by filing an issue at

<a href=\\"https://github.com/source-academy/cadet-frontend\\">
https://github.com/source-academy/cadet-frontend
</a>

and we will get it fixed as soon as possible.
</div>
</div>
</Blueprint3.NonIdealState>"
`;
12 changes: 8 additions & 4 deletions src/features/sicp/parser/ParseJson.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ const handleFootnote = (obj: JsonType, refs: React.MutableRefObject<{}>) => {
return (
<div>
{obj['count'] === 1 && <hr />}
<div ref={ref => (refs.current[obj['id']!] = ref)} className="sicp-footnote">
<div className="sicp-footnote">
<div ref={ref => (refs.current[obj['id']!] = ref)} />
<a href={obj['href']}>{'[' + obj['count'] + '] '}</a>
{parseArr(obj['child']!, refs)}
</div>
Expand Down Expand Up @@ -113,7 +114,8 @@ const handleSnippet = (obj: JsonType) => {
};

const handleFigure = (obj: JsonType, refs: React.MutableRefObject<{}>) => (
<div ref={ref => (refs.current[obj['id']!] = ref)} className="sicp-figure">
<div className="sicp-figure">
<div ref={ref => (refs.current[obj['id']!] = ref)} />
{handleImage(obj, refs)}
{obj['captionName'] && (
<h5 className="sicp-caption">
Expand Down Expand Up @@ -152,7 +154,8 @@ const handleTD = (obj: JsonType, refs: React.MutableRefObject<{}>, index: intege

const handleExercise = (obj: JsonType, refs: React.MutableRefObject<{}>) => {
return (
<div ref={ref => (refs.current[obj['id']!] = ref)}>
<div>
<div ref={ref => (refs.current[obj['id']!] = ref)} />
<SicpExercise
title={obj['title']!}
body={parseArr(obj['child']!, refs)}
Expand Down Expand Up @@ -253,7 +256,8 @@ export const processingFunctions = {

TEXT: (obj: JsonType, refs: React.MutableRefObject<{}>) => (
<>
<div ref={ref => (refs.current[obj['id']!] = ref)} className="sicp-text">
<div className="sicp-text">
<div ref={ref => (refs.current[obj['id']!] = ref)} />
{parseArr(obj['child']!, refs)}
</div>
<br />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,18 +115,21 @@ exports[`Parse epigraph EPIGRAPH with title successful 1`] = `

exports[`Parse exercise EXERCISE with solution successful 1`] = `
"<div>
<div />
<SicpExercise title={[undefined]} body={{...}} solution={{...}} />
</div>"
`;

exports[`Parse exercise EXERCISE without solution successful 1`] = `
"<div>
<div />
<SicpExercise title=\\"Title\\" body={{...}} solution={[undefined]} />
</div>"
`;

exports[`Parse figures FIGURE with image and scale successful 1`] = `
"<div className=\\"sicp-figure\\">
<div />
<img src=\\"https://source-academy.github.io/sicp/sicp.png\\" alt=\\"id\\" width=\\"50%\\" />
<h5 className=\\"sicp-caption\\">
name
Expand All @@ -141,6 +144,7 @@ exports[`Parse figures FIGURE with image and scale successful 1`] = `

exports[`Parse figures FIGURE with image successful 1`] = `
"<div className=\\"sicp-figure\\">
<div />
<img src=\\"https://source-academy.github.io/sicp/sicp.png\\" alt=\\"id\\" width=\\"100%\\" />
<h5 className=\\"sicp-caption\\">
name
Expand All @@ -155,6 +159,7 @@ exports[`Parse figures FIGURE with image successful 1`] = `

exports[`Parse figures FIGURE with snippet successful 1`] = `
"<div className=\\"sicp-figure\\">
<div />
<Component body=\\"1 + 1;\\" id={[undefined]} initialEditorValueHash=\\"IwAg1CwNxA\\" initialFullProgramHash={[undefined]} initialPrependHash={[undefined]} output={[undefined]} />
<h5 className=\\"sicp-caption\\">
name
Expand All @@ -169,6 +174,7 @@ exports[`Parse figures FIGURE with snippet successful 1`] = `

exports[`Parse figures FIGURE with table successful 1`] = `
"<div className=\\"sicp-figure\\">
<div />
<table>
<tbody>
<tr>
Expand Down Expand Up @@ -220,6 +226,7 @@ exports[`Parse footnote DISPLAYFOOTNOTE count is 1 successful 1`] = `
"<div>
<hr />
<div className=\\"sicp-footnote\\">
<div />
<a href=\\"\\">
[1]
</a>
Expand All @@ -235,6 +242,7 @@ exports[`Parse footnote DISPLAYFOOTNOTE count is 1 successful 1`] = `
exports[`Parse footnote DISPLAYFOOTNOTE count is 2 successful 1`] = `
"<div>
<div className=\\"sicp-footnote\\">
<div />
<a href=\\"\\">
[2]
</a>
Expand Down Expand Up @@ -364,6 +372,7 @@ exports[`Parse section SECTION successful 1`] = `
<div>
<span>
<div className=\\"sicp-text\\">
<div />
<span>
<p>
Mock Text
Expand All @@ -379,6 +388,7 @@ exports[`Parse section SECTION successful 1`] = `
</span>
<span>
<div className=\\"sicp-text\\">
<div />
<span>
<p>
Mock Text
Expand Down
Loading