Skip to content

Commit

Permalink
Merge pull request #24 from hpi-swa-teaching/refactor-frontend
Browse files Browse the repository at this point in the history
Refactor frontend
  • Loading branch information
florian-papsdorf authored Aug 7, 2020
2 parents 0cda128 + 88eeaaf commit 0db9178
Show file tree
Hide file tree
Showing 68 changed files with 677 additions and 801 deletions.
13 changes: 7 additions & 6 deletions app/src/components/ErrorIndicator/ErrorIndicator.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import PropTypes from 'prop-types';

import './ErrorIndicator.css';

// TODO: do we need any tests for this component?
// TODO: Fix error message is shown when reloading the page without searching
const ErrorIndicator = props => {
const {
errorConditions,
errorMessage,
errorState: existsError,
errorStateSetter: setExistsError
errorStateSetter: setExistsError,
isActive
} = props;

useEffect(
Expand All @@ -23,7 +22,7 @@ const ErrorIndicator = props => {
[errorConditions, existsError, setExistsError]
);

return existsError ? <div className="errorText">{errorMessage}</div> : null;
return existsError && isActive ? <div className="errorText">{errorMessage}</div> : null;
};

ErrorIndicator.propTypes = {
Expand All @@ -40,11 +39,13 @@ ErrorIndicator.propTypes = {
).isRequired,
errorMessage: PropTypes.string,
errorState: PropTypes.bool.isRequired,
errorStateSetter: PropTypes.func.isRequired
errorStateSetter: PropTypes.func.isRequired,
isActive: PropTypes.bool
};

ErrorIndicator.defaultProps = {
errorMessage: 'An error occurred. Please check your input or contact support.'
errorMessage: 'An error occurred. Please check your input or contact support.',
isActive: true
};

export default ErrorIndicator;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import LoadingIndicator from '../../LoadingIndicator/LoadingIndicator';
import { getAllMethodsOf, getClass } from '../../../utils/apiHandler';
import { getAllMethodsOf, getClass } from '../../../utils/BackendHandling/apiHandler';
import './ClassView.css';

const ClassView = ({ currentClass }) => {
Expand Down
98 changes: 31 additions & 67 deletions app/src/components/ExplorationViews/ClassView/ClassView.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,95 +4,59 @@ import { act } from 'react-dom/test-utils';
import ClassView from './ClassView';
import { cleanUpContainer, prepareContainer } from '../../../test-utils/test-helper';
import { baseURL } from '../../../config/constants';
import {
getClassMock,
getFetchMethodsMock,
getSampleClassName,
getSampleMethodsOfClassResponse
} from '../../../test-utils/apiMocks';

describe('Class View', () => {
let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = prepareContainer(container);
});

let container = null;
beforeEach(() => {
// setup a DOM element as a render target
container = prepareContainer(container);
});

afterEach(() => {
// cleanup on exiting
container = cleanUpContainer(container);
});
afterEach(() => {
// cleanup on exiting
container = cleanUpContainer(container);
jest.clearAllMocks();
});

describe('ClassView', () => {
it('should display the total count of fetched methods', async () => {
const sampleMethodsOfClassResponse = {
classMethods: ['newStarted', 'newStartedOn:'],
count: { classMethods: 2, total: 12, instanceMethods: 10 },
instanceMethods: [
'getHelpPagesFrom:',
'getClassMethodTextFrom:named:',
'getInstanceMethodFrom:named:',
'getMethods:',
'getClasses',
'getHelpPageFrom:at:',
'helloWorld:',
'getClassMethodFrom:named:',
'getHelpBookFrom:',
'getInstanceMethodTextFrom:named:'
]
};

const fetchMock = jest.spyOn(global, 'fetch').mockImplementation(() =>
Promise.resolve({
json: () => sampleMethodsOfClassResponse
})
);
const fetchMock = getFetchMethodsMock();

await act(async () => {
render(<ClassView currentClass="test" />, container);
render(<ClassView currentClass={getSampleClassName()} />, container);
});

expect(fetchMock).toHaveBeenCalledWith(`${baseURL}/env/classes/test/methods`);
expect(fetchMock).toHaveBeenCalledWith(`${baseURL}/env/classes/test`);

expect(container).toHaveTextContent(sampleMethodsOfClassResponse.count.total);
expect(fetchMock).toHaveBeenCalledWith(
`${baseURL}/env/classes/${getSampleClassName()}/methods`
);
expect(fetchMock).toHaveBeenCalledWith(`${baseURL}/env/classes/${getSampleClassName()}`);

global.fetch.mockRestore();
expect(container).toHaveTextContent(getSampleMethodsOfClassResponse().count.total);
});
it('should display class view without comment', async () => {
const sampleMethodsOfClassResponse = {
classMethods: ['newStarted', 'newStartedOn:'],
count: { classMethods: 2, total: 12, instanceMethods: 10 },
instanceMethods: []
};

jest.spyOn(global, 'fetch').mockImplementation(() =>
Promise.resolve({
json: () => sampleMethodsOfClassResponse
})
);
it('should display class view without comment', async () => {
getFetchMethodsMock();

await act(async () => {
render(<ClassView currentClass="test" />, container);
render(<ClassView currentClass={getSampleClassName()} />, container);
});

expect(container.querySelector('.comment')).toBeNull();

global.fetch.mockRestore();
});
it('should display class view with comment', async () => {
const sampleClassResponse = {
count: { classMethods: 2, total: 12, instanceMethods: 10 },
hasClassComment: true,
classComment: 'this is a class comment'
};

jest.spyOn(global, 'fetch').mockImplementation(() =>
Promise.resolve({
json: () => sampleClassResponse
})
);
it('should display class view with comment', async () => {
getClassMock();

await act(async () => {
render(<ClassView currentClass="test" />, container);
render(<ClassView currentClass={getSampleClassName()} />, container);
});

expect(container.querySelector('.comment')).toBeInTheDocument();
expect(container.querySelector('.commentText')).toHaveTextContent('this is a class comment');

global.fetch.mockRestore();
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import React from 'react';
import '../../../styles/landingViews.css';

// TODO: style component
const ExplorationLandingView = () => (
<div>
<h1>Welcome to Småprat!</h1>
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/ExplorationViews/HelpView/HelpView.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { getContentOfBook } from '../../../utils/apiHandler';
import { getContentOfBook } from '../../../utils/BackendHandling/apiHandler';
import LoadingIndicator from '../../LoadingIndicator/LoadingIndicator';

const HelpView = ({ bookName }) => {
Expand Down
52 changes: 9 additions & 43 deletions app/src/components/ExplorationViews/HelpView/HelpView.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { act } from 'react-dom/test-utils';
import HelpView from './HelpView';
import { baseURL } from '../../../config/constants';
import { cleanUpContainer, prepareContainer } from '../../../test-utils/test-helper';
import { getContentOfBookMock, getSampleClassName } from '../../../test-utils/apiMocks';

let container = null;
beforeEach(() => {
Expand All @@ -16,56 +17,21 @@ afterEach(() => {
container = cleanUpContainer(container);
});

describe('ClassView', () => {
describe('Help View', () => {
it('should display fetched books', async () => {
const sampleHelpClassPagesResponse = {
pages: [
{
pageName: 'introduction',
isGivenByClass: true
},
{
pageName: 'HelpHowToHelpTopics',
isGivenByClass: false
},
{
pageName: 'HelpAPIDocumentation',
isGivenByClass: false
}
]
};

const sampleHelpPageResponse = {
content:
'WELCOME TO THE HELP SYSTEM\r\rThe help system is a simple user interface to display help contents to the user. It can be accessed from the world menu using "Tools" -> "Help Browser" or by evaluating \'HelpBrowser open\' in a workspace.\r\rThere is a predefined mechanism allowing you to have help contents stored as source code using methods in specific help provider classes. This allows you to manage the help texts using the standard development tools. But this is only one possible representation.\r',
pageName: 'introduction',
title: 'Introduction'
};

const fetchMock = jest.spyOn(global, 'fetch').mockImplementation(path => {
switch (path) {
case `${baseURL}/help/testBookName/pages`:
return Promise.resolve({
json: () => sampleHelpClassPagesResponse
});
case `${baseURL}/help/testBookName/pages/introduction`:
return Promise.resolve({
json: () => sampleHelpPageResponse
});
default:
return null;
}
});
const fetchMock = getContentOfBookMock();

await act(async () => {
render(<HelpView bookName="testBookName" />, container);
render(<HelpView bookName={getSampleClassName()} />, container);
});

expect(fetchMock).toHaveBeenCalledWith(`${baseURL}/help/testBookName/pages`);
expect(fetchMock).toHaveBeenCalledWith(`${baseURL}/help/testBookName/pages/introduction`);
expect(fetchMock).toHaveBeenCalledWith(`${baseURL}/help/${getSampleClassName()}/pages`);
expect(fetchMock).toHaveBeenCalledWith(
`${baseURL}/help/${getSampleClassName()}/pages/introduction`
);
expect(fetchMock).toHaveBeenCalledTimes(2);

expect(container.querySelector('h1')).toHaveTextContent('testBookName');
expect(container.querySelector('h1')).toHaveTextContent(getSampleClassName());

global.fetch.mockRestore();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { docco } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
import LoadingIndicator from '../../LoadingIndicator/LoadingIndicator';
import { getMethodInfo, getMethodText } from '../../../utils/apiHandler';
import { getMethodInfo, getMethodText } from '../../../utils/BackendHandling/apiHandler';
import './MethodView.css';

const MethodView = ({ currentClass, site, currentMethod }) => {
Expand Down
63 changes: 27 additions & 36 deletions app/src/components/ExplorationViews/MethodView/MethodView.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@ import { act } from 'react-dom/test-utils';
import { baseURL } from '../../../config/constants';
import MethodView from './MethodView';
import { cleanUpContainer, prepareContainer } from '../../../test-utils/test-helper';
import {
getFetchMethodInfoAndCodeMock,
getSampleClassName,
getSampleMethodName,
getSampleSide
} from '../../../test-utils/apiMocks';

let container = null;

beforeEach(() => {
jest.clearAllMocks();
// setup a DOM element as a render target
Expand All @@ -17,51 +24,35 @@ afterEach(() => {
container = cleanUpContainer(container);
});

describe('MethodView', () => {
describe('Method View', () => {
it('should display a current method', async () => {
const className = 'className';
const site = 'site';
const methodName = 'methodName';

const sampleMethodView = {
hasPrecodeComment: true,
precodeComment:
'This is the main entry point for the JSON parser. See also readFrom: on the class site.'
};

const sampleMethodViewText = `${methodName}\n\t^ 'MethodText-was-shown!'.`;

const fetchMock = jest.spyOn(global, 'fetch').mockImplementation(arg => {
switch (arg) {
case `${baseURL}/env/classes/${className}/methods/${site}/${methodName}`:
return Promise.resolve({
json: () => sampleMethodView
});
case `${baseURL}/env/classes/${className}/methods/${site}/${methodName}/text`:
return Promise.resolve({
text: () => sampleMethodViewText
});
default:
break;
}
return null;
});
const path = `${baseURL}/env/classes/${getSampleClassName()}/methods/${getSampleSide()}/${getSampleMethodName()}`;
const fetchMock = getFetchMethodInfoAndCodeMock(
getSampleClassName(),
getSampleSide(),
getSampleMethodName()
);

await act(async () => {
render(
<MethodView currentClass={className} site={site} currentMethod={methodName} />,
<MethodView
currentClass={getSampleClassName()}
site={getSampleSide()}
currentMethod={getSampleMethodName()}
/>,
container
);
});

expect(fetchMock).toHaveBeenCalledWith(
`${baseURL}/env/classes/${className}/methods/${site}/${methodName}`
);
expect(fetchMock).toHaveBeenCalledWith(
`${baseURL}/env/classes/${className}/methods/${site}/${methodName}/text`
expect(fetchMock).toHaveBeenCalledWith(path);

expect(fetchMock).toHaveBeenCalledWith(`${path}/text`);

expect(container.querySelector('h1')).toHaveTextContent(getSampleMethodName());

expect(container.querySelector('code')).toHaveTextContent(
'readFrom: aStream ^ self new readFrom: aStream.'
);
expect(container.querySelector('h1')).toHaveTextContent(methodName);
expect(container.querySelector('code')).toHaveTextContent('MethodText-was-shown!');

global.fetch.mockRestore();
});
Expand Down
Loading

0 comments on commit 0db9178

Please sign in to comment.