Add tests

This commit is contained in:
phntxx 2021-06-21 16:52:16 +02:00
parent aa61b2fb76
commit 0612312e13
21 changed files with 642 additions and 113 deletions

View file

@ -1,34 +1,9 @@
module.exports = { module.exports = {
extends: ["eslint:recommended", "plugin:react-hooks/recommended"], extends: ["eslint:recommended", "plugin:react-hooks/recommended"],
rules: { rules: {
orderedImports: true, maxClassesPerFile: 0,
completedDocs: [ maxLineLength: 0,
true, memberOrdering: 0,
{ variableName: 0,
enums: true,
functions: {
visibilities: ["exported"],
},
interfaces: {
visibilities: ["exported"],
},
methods: {
tags: {
content: {},
existence: ["inheritdoc", "override"],
},
},
types: {
visibilities: ["exported"],
},
variables: {
visibilities: ["exported"],
},
},
],
maxClassesPerFile: false,
maxLineLength: false,
memberOrdering: false,
variableName: false,
}, },
}; };

View file

@ -1,4 +1,3 @@
import { useEffect } from "react";
import Icon from "./icon"; import Icon from "./icon";
import styled from "styled-components"; import styled from "styled-components";
import selectedTheme from "../lib/theme"; import selectedTheme from "../lib/theme";

View file

@ -8,6 +8,7 @@ interface IIconProps {
} }
interface IIconButtonProps { interface IIconButtonProps {
testid?: string;
icon: string; icon: string;
onClick: (e: React.FormEvent) => void; onClick: (e: React.FormEvent) => void;
} }
@ -38,7 +39,7 @@ const IconContainer = styled.i`
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
font-feature-settings: "liga"; font-feature-settings: "liga";
font-size: ${(props) => props.theme}; font-size: ${(props) => props.about};
color: ${(props) => props.color}; color: ${(props) => props.color};
`; `;
@ -48,7 +49,7 @@ const IconContainer = styled.i`
* @returns {React.ReactNode} the icon node * @returns {React.ReactNode} the icon node
*/ */
export const Icon = ({ name, size }: IIconProps) => ( export const Icon = ({ name, size }: IIconProps) => (
<IconContainer color={selectedTheme.mainColor} theme={size}> <IconContainer color={selectedTheme.mainColor} about={size}>
{name} {name}
</IconContainer> </IconContainer>
); );
@ -58,8 +59,8 @@ export const Icon = ({ name, size }: IIconProps) => (
* @param {IIconProps} props - The props of the given IconButton * @param {IIconProps} props - The props of the given IconButton
* @returns {React.ReactNode} the icon button node * @returns {React.ReactNode} the icon button node
*/ */
export const IconButton = ({ icon, onClick }: IIconButtonProps) => ( export const IconButton = ({ testid, icon, onClick }: IIconButtonProps) => (
<StyledButton onClick={onClick}> <StyledButton data-testid={testid} onClick={onClick}>
<Icon name={icon} /> <Icon name={icon} />
</StyledButton> </StyledButton>
); );

View file

@ -41,7 +41,7 @@ export interface IImprintProps {
text: string; text: string;
} }
interface IImprintComponentProps { export interface IImprintComponentProps {
imprint: IImprintProps; imprint: IImprintProps;
} }
@ -59,7 +59,7 @@ interface IImprintFieldProps {
* @param {IImprintFieldComponentProps} props data for the field * @param {IImprintFieldComponentProps} props data for the field
* @returns {React.ReactNode} the imprint field component * @returns {React.ReactNode} the imprint field component
*/ */
const ImprintField = ({ field }: IImprintFieldComponentProps) => ( export const ImprintField = ({ field }: IImprintFieldComponentProps) => (
<Link href={field.link}>{field.text}</Link> <Link href={field.link}>{field.text}</Link>
); );
@ -82,8 +82,10 @@ const Imprint = ({ imprint }: IImprintComponentProps) => (
condition={!window.location.href.endsWith("#imprint")} condition={!window.location.href.endsWith("#imprint")}
onClose={() => { onClose={() => {
if (window.location.href.endsWith("#imprint")) { if (window.location.href.endsWith("#imprint")) {
let location = window.location.href.replace("#imprint", ""); window.location.href = window.location.href.replace(
window.location.href = location; "#imprint",
"",
);
} }
}} }}
> >

View file

@ -38,7 +38,7 @@ const TitleContainer = styled.div`
justify-content: space-between; justify-content: space-between;
`; `;
interface IModalProps { export interface IModalProps {
element: string; element: string;
icon?: string; icon?: string;
text?: string; text?: string;
@ -72,15 +72,27 @@ const Modal = ({
return ( return (
<> <>
{element === "icon" && ( {element === "icon" && (
<IconButton icon={icon ?? ""} onClick={() => closeModal()} /> <IconButton
icon={icon ?? ""}
testid="toggle-button"
onClick={() => closeModal()}
/>
)} )}
{element === "text" && <Text onClick={() => closeModal()}>{text}</Text>} {element === "text" && (
<Text data-testid="toggle-button" onClick={() => closeModal()}>
{text}
</Text>
)}
<ModalContainer hidden={modalHidden}> <ModalContainer hidden={modalHidden}>
<TitleContainer> <TitleContainer>
<Headline>{title}</Headline> <Headline>{title}</Headline>
<IconButton icon="close" onClick={() => closeModal()} /> <IconButton
icon="close"
testid="close-button"
onClick={() => closeModal()}
/>
</TitleContainer> </TitleContainer>
{children} {children}
</ModalContainer> </ModalContainer>

View file

@ -43,33 +43,14 @@ export interface ISearchProviderProps {
prefix: string; prefix: string;
} }
interface ISearchBarProps { export interface ISearchBarProps {
providers: Array<ISearchProviderProps> | undefined; providers: Array<ISearchProviderProps> | undefined;
} }
/** export const handleQueryWithProvider = (
* Renders a search bar providers: Array<ISearchProviderProps> | undefined,
* @param {ISearchBarProps} props - The search providers for the search bar to use query: string,
*/ ) => {
const SearchBar = ({ providers }: ISearchBarProps) => {
let [input, setInput] = useState<string>("");
let [buttonsHidden, setButtonsHidden] = useState<boolean>(true);
useEffect(() => setButtonsHidden(input === ""), [input]);
const handleSearchQuery = (e: React.FormEvent) => {
var query: string = input || "";
if (query.split(" ")[0].includes("/")) {
handleQueryWithProvider(query);
} else {
window.location.href = "https://google.com/search?q=" + query;
}
e.preventDefault();
};
const handleQueryWithProvider = (query: string) => {
let queryArray: Array<string> = query.split(" "); let queryArray: Array<string> = query.split(" ");
let prefix: string = queryArray[0]; let prefix: string = queryArray[0];
@ -89,12 +70,35 @@ const SearchBar = ({ providers }: ISearchBarProps) => {
if (!providerFound) if (!providerFound)
window.location.href = "https://google.com/search?q=" + query; window.location.href = "https://google.com/search?q=" + query;
};
/**
* Renders a search bar
* @param {ISearchBarProps} props - The search providers for the search bar to use
*/
const SearchBar = ({ providers }: ISearchBarProps) => {
let [input, setInput] = useState<string>("");
let [buttonsHidden, setButtonsHidden] = useState<boolean>(true);
useEffect(() => setButtonsHidden(input === ""), [input]);
const handleSearchQuery = (e: React.FormEvent) => {
var query: string = input || "";
if (query.split(" ")[0].includes("/")) {
handleQueryWithProvider(providers, query);
} else {
window.location.href = "https://google.com/search?q=" + query;
}
e.preventDefault();
}; };
return ( return (
<Search onSubmit={(e) => handleSearchQuery(e)}> <Search onSubmit={(e) => handleSearchQuery(e)}>
<SearchInput <SearchInput
type="text" type="text"
data-testid="search-input"
value={input} value={input}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setInput(e.target.value) setInput(e.target.value)
@ -102,12 +106,17 @@ const SearchBar = ({ providers }: ISearchBarProps) => {
></SearchInput> ></SearchInput>
<SearchButton <SearchButton
type="button" type="button"
data-testid="search-clear"
onClick={() => setInput("")} onClick={() => setInput("")}
hidden={buttonsHidden} hidden={buttonsHidden}
> >
Clear Clear
</SearchButton> </SearchButton>
<SearchButton type="submit" hidden={buttonsHidden}> <SearchButton
type="submit"
data-testid="search-submit"
hidden={buttonsHidden}
>
Search Search
</SearchButton> </SearchButton>
</Search> </Search>

View file

@ -4,47 +4,51 @@ import styled from "styled-components";
import Select, { ValueType } from "react-select"; import Select, { ValueType } from "react-select";
import { ISearchProviderProps } from "./searchBar"; import { ISearchProviderProps } from "./searchBar";
import selectedTheme, { setTheme, IThemeProps } from "../lib/theme"; import selectedTheme, {
defaultTheme,
setTheme,
IThemeProps,
} from "../lib/theme";
import { Button, SubHeadline } from "./elements"; import { Button, SubHeadline } from "./elements";
import Modal from "./modal"; import Modal from "./modal";
const FormContainer = styled.div` export const FormContainer = styled.div`
display: grid; display: grid;
grid-template-columns: auto auto auto; grid-template-columns: auto auto auto;
`; `;
const Table = styled.table` export const Table = styled.table`
font-weight: 400; font-weight: 400;
background: none; background: none;
color: ${selectedTheme.mainColor}; color: ${selectedTheme.mainColor};
`; `;
const TableRow = styled.tr` export const TableRow = styled.tr`
border-bottom: 1px solid ${selectedTheme.mainColor}; border-bottom: 1px solid ${selectedTheme.mainColor};
`; `;
const TableCell = styled.td` export const TableCell = styled.td`
background: none; background: none;
padding-top: 0.5rem; padding-top: 0.5rem;
`; `;
const HeadCell = styled.th` export const HeadCell = styled.th`
font-weight: 700; font-weight: 700;
background: none; background: none;
`; `;
const Section = styled.div` export const Section = styled.div`
padding: 1rem 0; padding: 1rem 0;
`; `;
const SectionHeadline = styled(SubHeadline)` export const SectionHeadline = styled(SubHeadline)`
width: 100%; width: 100%;
border-bottom: 1px solid ${selectedTheme.accentColor}; border-bottom: 1px solid ${selectedTheme.accentColor};
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
`; `;
const SelectorStyle: any = { export const SelectorStyle: any = {
container: (base: any): any => ({ container: (base: any): any => ({
...base, ...base,
margin: "0 2px", margin: "0 2px",
@ -113,7 +117,7 @@ interface ISettingsProps {
* @param {Array<ISearchProviderProps>} providers - the list of search providers * @param {Array<ISearchProviderProps>} providers - the list of search providers
*/ */
const Settings = ({ themes, providers }: ISettingsProps) => { const Settings = ({ themes, providers }: ISettingsProps) => {
const [newTheme, setNewTheme] = useState<IThemeProps>(); const [newTheme, setNewTheme] = useState<IThemeProps>(defaultTheme);
if (themes || providers) { if (themes || providers) {
return ( return (
@ -123,6 +127,7 @@ const Settings = ({ themes, providers }: ISettingsProps) => {
<SectionHeadline>Theme:</SectionHeadline> <SectionHeadline>Theme:</SectionHeadline>
<FormContainer> <FormContainer>
<Select <Select
classNamePrefix="list"
options={themes} options={themes}
defaultValue={selectedTheme} defaultValue={selectedTheme}
onChange={(e: ValueType<IThemeProps, false>) => { onChange={(e: ValueType<IThemeProps, false>) => {
@ -130,10 +135,18 @@ const Settings = ({ themes, providers }: ISettingsProps) => {
}} }}
styles={SelectorStyle} styles={SelectorStyle}
/> />
<Button onClick={() => setTheme(JSON.stringify(newTheme))}> <Button
data-testid="button-submit"
onClick={() => setTheme(newTheme)}
>
Apply Apply
</Button> </Button>
<Button onClick={() => window.location.reload()}>Refresh</Button> <Button
data-testid="button-refresh"
onClick={() => window.location.reload()}
>
Refresh
</Button>
</FormContainer> </FormContainer>
</Section> </Section>
)} )}

View file

@ -17,7 +17,7 @@ const inProduction = process.env.NODE_ENV === "production";
* @returns - The response in JSON * @returns - The response in JSON
* @throws - Error with given error message if request failed * @throws - Error with given error message if request failed
*/ */
const handleResponse = (response: Response) => { export const handleResponse = (response: Response) => {
if (response.ok) return response.json(); if (response.ok) return response.json();
throw new Error(errorMessage); throw new Error(errorMessage);
}; };
@ -56,7 +56,7 @@ export interface IGreeterDataProps {
/** /**
* Default values for the respective state variables * Default values for the respective state variables
*/ */
const defaults = { export const defaults = {
app: { app: {
categories: [], categories: [],
apps: [], apps: [],
@ -143,7 +143,7 @@ const defaults = {
* @param {string} type - The type of fetch request that threw an error * @param {string} type - The type of fetch request that threw an error
* @param {Error} error - The error itself * @param {Error} error - The error itself
*/ */
const handleError = (status: string, error: Error) => { export const handleError = (status: string, error: Error) => {
switch (status) { switch (status) {
case "apps": case "apps":
return { ...defaults.app, error: error.message }; return { ...defaults.app, error: error.message };
@ -165,7 +165,7 @@ const handleError = (status: string, error: Error) => {
/** /**
* Fetches all of the data by doing fetch requests (only available in production) * Fetches all of the data by doing fetch requests (only available in production)
*/ */
const fetchProduction = Promise.all([ export const fetchProduction = Promise.all([
fetch("/data/apps.json") fetch("/data/apps.json")
.then(handleResponse) .then(handleResponse)
.catch((error: Error) => handleError("apps", error)), .catch((error: Error) => handleError("apps", error)),
@ -189,7 +189,7 @@ const fetchProduction = Promise.all([
/** /**
* Fetches all of the data by importing it (only available in development) * Fetches all of the data by importing it (only available in development)
*/ */
const fetchDevelopment = Promise.all([ export const fetchDevelopment = Promise.all([
import("../data/apps.json"), import("../data/apps.json"),
import("../data/bookmarks.json"), import("../data/bookmarks.json"),
import("../data/search.json"), import("../data/search.json"),

View file

@ -6,7 +6,7 @@ export interface IThemeProps {
backgroundColor: string; backgroundColor: string;
} }
const defaultTheme: IThemeProps = { export const defaultTheme: IThemeProps = {
label: "Classic", label: "Classic",
value: 0, value: 0,
mainColor: "#000000", mainColor: "#000000",
@ -18,8 +18,8 @@ const defaultTheme: IThemeProps = {
* Writes a given theme into localStorage * Writes a given theme into localStorage
* @param {string} theme - the theme that shall be saved (in stringified JSON) * @param {string} theme - the theme that shall be saved (in stringified JSON)
*/ */
export const setTheme = (theme: string) => { export const setTheme = (theme: IThemeProps) => {
if (theme !== undefined) localStorage.setItem("theme", theme); localStorage.setItem("theme", JSON.stringify(theme));
window.location.reload(); window.location.reload();
}; };
@ -30,9 +30,8 @@ export const setTheme = (theme: string) => {
export const getTheme = (): IThemeProps => { export const getTheme = (): IThemeProps => {
let selectedTheme = defaultTheme; let selectedTheme = defaultTheme;
if (localStorage.getItem("theme") !== null) { let theme = localStorage.getItem("theme");
selectedTheme = JSON.parse(localStorage.getItem("theme") || "{}"); if (theme !== null) selectedTheme = JSON.parse(theme || "{}");
}
return selectedTheme; return selectedTheme;
}; };

View file

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Tests Button 1`] = `[Function]`;
exports[`Tests Headline 1`] = `[Function]`;
exports[`Tests Lists 1`] = `[Function]`;
exports[`Tests SubHeadline 1`] = `[Function]`;

View file

@ -0,0 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`imprint.tsx Tests Imprint 1`] = `[Function]`;
exports[`imprint.tsx Tests ImprintField 1`] = `[Function]`;

View file

@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`modal.tsx Tests modal with icon 1`] = `[Function]`;
exports[`modal.tsx Tests modal with icon button 1`] = `[Function]`;
exports[`modal.tsx Tests modal with neither 1`] = `[Function]`;
exports[`modal.tsx Tests modal with text button 1`] = `[Function]`;

View file

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`searchBar.tsx Tests SearchBar rendering 1`] = `[Function]`;

View file

@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`settings.tsx Tests forms 1`] = `[Function]`;
exports[`settings.tsx Tests sections 1`] = `[Function]`;
exports[`settings.tsx Tests settings rendering 1`] = `[Function]`;
exports[`settings.tsx Tests settings rendering 2`] = `[Function]`;
exports[`settings.tsx Tests settings rendering 3`] = `[Function]`;
exports[`settings.tsx Tests settings rendering 4`] = `[Function]`;
exports[`settings.tsx Tests tables 1`] = `[Function]`;

View file

@ -0,0 +1,39 @@
import { render } from "@testing-library/react";
import {
ListContainer,
Headline,
SubHeadline,
ItemList,
Item,
Button,
} from "../../components/elements";
it("Tests Lists", () => {
const { asFragment } = render(
<ListContainer>
<ItemList>
<Item>Test</Item>
</ItemList>
</ListContainer>,
);
expect(asFragment).toMatchSnapshot();
});
it("Tests Headline", () => {
const { asFragment } = render(<Headline>Test</Headline>);
expect(asFragment).toMatchSnapshot();
});
it("Tests SubHeadline", () => {
const { asFragment } = render(<SubHeadline>Test</SubHeadline>);
expect(asFragment).toMatchSnapshot();
});
it("Tests Button", () => {
const { asFragment } = render(<Button>Test</Button>);
expect(asFragment).toMatchSnapshot();
});

View file

@ -0,0 +1,61 @@
import { fireEvent, render } from "@testing-library/react";
import Imprint, { IImprintProps, ImprintField } from "../../components/imprint";
const props: IImprintProps = {
name: {
text: "Test Name",
link: "#",
},
address: {
text: "Test Address",
link: "#",
},
phone: {
text: "Test Phone",
link: "#",
},
email: {
text: "Test Email",
link: "#",
},
url: {
text: "Test URL",
link: "#",
},
text: "This is a test!",
};
describe("imprint.tsx", () => {
beforeEach(() => {
delete global.window.location;
global.window = Object.create(window);
global.window.location = {
port: "123",
protocol: "http:",
hostname: "localhost",
href: "test",
};
});
it("Tests Imprint", () => {
const { asFragment } = render(<Imprint imprint={props} />);
expect(asFragment).toMatchSnapshot();
});
it("Tests #imprint", () => {
const location = window.location.href;
window.location.href = location + "#imprint";
const imprintModal = render(<Imprint imprint={props} />);
fireEvent.click(imprintModal.getByTestId("toggle-button"));
//fireEvent.click(imprintModal.getByTestId("close-button"));
expect(window.location.href).toEqual(location);
});
it("Tests ImprintField", () => {
const { asFragment } = render(<ImprintField field={props.name} />);
expect(asFragment).toMatchSnapshot();
});
});

View file

@ -0,0 +1,78 @@
import { fireEvent, render } from "@testing-library/react";
import Modal, { IModalProps } from "../../components/modal";
const iconProps: IModalProps = {
element: "icon",
icon: "bug_report",
title: "Test Modal",
onClose: jest.fn(),
children: <p>Hello</p>,
};
const invalidIconProps: IModalProps = {
element: "icon",
title: "Test Modal",
onClose: jest.fn(),
children: <p>Hello</p>,
};
const textProps: IModalProps = {
element: "text",
text: "Test",
title: "Test Modal",
onClose: jest.fn(),
children: <p>Hello</p>,
};
const noneProps: IModalProps = {
element: "none",
title: "Test Modal",
children: <p>Hello</p>,
};
const setup = (props: IModalProps) => {
const modal = render(
<Modal
element={props.element}
icon={props.icon}
text={props.text}
title={props.title}
onClose={props.onClose}
>
{props.children}
</Modal>,
);
return modal;
};
describe("modal.tsx", () => {
it("Tests modal with icon button", () => {
const modal = setup(iconProps);
expect(modal.asFragment).toMatchSnapshot();
fireEvent.click(modal.getByTestId("toggle-button"));
fireEvent.click(modal.getByTestId("close-button"));
expect(iconProps.onClose).toHaveBeenCalledTimes(2);
});
it("Tests modal with text button", () => {
const modal = setup(textProps);
expect(modal.asFragment).toMatchSnapshot();
fireEvent.click(modal.getByTestId("toggle-button"));
fireEvent.click(modal.getByTestId("close-button"));
expect(textProps.onClose).toHaveBeenCalledTimes(2);
});
it("Tests modal with neither", () => {
const modal = setup(noneProps);
expect(modal.asFragment).toMatchSnapshot();
});
it("Tests modal with icon", () => {
const modal = setup(invalidIconProps);
expect(modal.asFragment).toMatchSnapshot();
fireEvent.click(modal.getByTestId("toggle-button"));
fireEvent.click(modal.getByTestId("close-button"));
expect(invalidIconProps.onClose).toHaveBeenCalledTimes(2);
});
});

View file

@ -0,0 +1,101 @@
import { fireEvent, render } from "@testing-library/react";
import SearchBar, {
handleQueryWithProvider,
ISearchProviderProps,
ISearchBarProps,
} from "../../components/searchBar";
const providers: Array<ISearchProviderProps> = [
{
name: "Allmusic",
url: "https://www.allmusic.com/search/all/",
prefix: "/a",
},
{
name: "Discogs",
url: "https://www.discogs.com/search/?q=",
prefix: "/di",
},
{
name: "Duck Duck Go",
url: "https://duckduckgo.com/?q=",
prefix: "/d",
},
];
const setup = () => {
const searchBar = render(<SearchBar providers={providers} />);
const input = searchBar.getByTestId("search-input");
const clearButton = searchBar.getByTestId("search-clear");
const submitButton = searchBar.getByTestId("search-submit");
return {
searchBar,
input,
clearButton,
submitButton,
};
};
describe("searchBar.tsx", () => {
beforeEach(() => {
delete global.window.location;
global.window = Object.create(window);
global.window.location = {
port: "123",
protocol: "http:",
hostname: "localhost",
};
});
it("Tests SearchBar rendering", () => {
const { asFragment } = render(<SearchBar providers={providers} />);
expect(asFragment).toMatchSnapshot();
});
it("Tests handleQueryWithProvider", () => {
providers.forEach((provider: ISearchProviderProps) => {
handleQueryWithProvider(providers, provider.prefix + " test");
expect(window.location.href).toEqual(provider.url + "test");
});
});
it("Tests handleQueryWithProvider default", () => {
handleQueryWithProvider(providers, "test");
expect(window.location.href).toEqual("https://google.com/search?q=test");
});
it("Tests handleQueryWithProvider without providers", () => {
handleQueryWithProvider(undefined, "test");
expect(window.location.href).toEqual("https://google.com/search?q=test");
});
it("Tests SearchBar component with default search", () => {
const { input, submitButton } = setup();
fireEvent.change(input, { target: { value: "test" } });
fireEvent.click(submitButton);
expect(window.location.href).toEqual("https://google.com/search?q=test");
});
it("Tests SearchBar component with other search", () => {
const { input, submitButton } = setup();
fireEvent.change(input, { target: { value: "/a test" } });
fireEvent.click(submitButton);
expect(window.location.href).toEqual(
"https://www.allmusic.com/search/all/test",
);
});
it("Tests SearchBar component clear", () => {
const { input, clearButton, submitButton } = setup();
fireEvent.change(input, { target: { value: "/a test" } });
fireEvent.click(clearButton);
fireEvent.click(submitButton);
expect(window.location.href).toEqual("https://google.com/search?q=");
});
});

View file

@ -0,0 +1,143 @@
import { fireEvent, render } from "@testing-library/react";
import Settings, {
FormContainer,
Table,
TableRow,
TableCell,
HeadCell,
Section,
SectionHeadline,
SelectorStyle,
} from "../../components/settings";
import { ISearchProviderProps } from "../../components/searchBar";
import { IThemeProps } from "../../lib/theme";
const themes: Array<IThemeProps> = [
{
label: "Classic",
value: 0,
mainColor: "#000000",
accentColor: "#1e272e",
backgroundColor: "#ffffff",
},
{
label: "Classic",
value: 0,
mainColor: "#000000",
accentColor: "#1e272e",
backgroundColor: "#ffffff",
},
];
const providers: Array<ISearchProviderProps> = [
{
name: "Allmusic",
url: "https://www.allmusic.com/search/all/",
prefix: "/a",
},
{
name: "Discogs",
url: "https://www.discogs.com/search/?q=",
prefix: "/di",
},
{
name: "Duck Duck Go",
url: "https://duckduckgo.com/?q=",
prefix: "/d",
},
];
const propsList = [
{
themes: themes,
providers: providers,
},
{
themes: themes,
providers: undefined,
},
{
themes: undefined,
providers: providers,
},
{
themes: undefined,
providers: undefined,
},
];
describe("settings.tsx", () => {
const location: Location = window.location;
8;
beforeEach(() => {
// @ts-ignore
delete window.location;
window.location = {
...location,
reload: jest.fn(),
};
});
it("Tests forms", () => {
const { asFragment } = render(<FormContainer />);
expect(asFragment).toMatchSnapshot();
});
it("Tests tables", () => {
const { asFragment } = render(
<Table>
<tbody>
<TableRow>
<HeadCell>Test</HeadCell>
</TableRow>
<TableRow>
<TableCell>Test</TableCell>
</TableRow>
</tbody>
</Table>,
);
expect(asFragment).toMatchSnapshot();
});
it("Tests sections", () => {
const { asFragment } = render(
<Section>
<SectionHeadline>Test</SectionHeadline>
</Section>,
);
expect(asFragment).toMatchSnapshot();
});
it("Tests settings rendering", () => {
propsList.forEach((props) => {
const settings = render(
<Settings themes={props.themes} providers={props.providers} />,
);
expect(settings.asFragment).toMatchSnapshot();
});
});
// TODO: Finish this test
it("Tests theme setting", () => {
const settings = render(
<Settings
themes={propsList[0].themes}
providers={propsList[0].providers}
/>,
);
const toggleButton = settings.getByTestId("toggle-button");
const submitButton = settings.getByTestId("button-submit");
const refreshButton = settings.getByTestId("button-refresh");
fireEvent.click(toggleButton);
fireEvent.click(submitButton);
});
});

View file

@ -0,0 +1,46 @@
import { ok } from "assert";
import useFetcher, {
defaults,
handleResponse,
handleError,
fetchProduction,
fetchDevelopment,
} from "../../lib/fetcher";
describe("fetcher.tsx", () => {
it("Tests handleResponse", () => {});
it("Tests handleError", () => {
expect(handleError("apps", Error("Test!"))).toEqual({
...defaults.app,
error: "Test!",
});
expect(handleError("bookmark", Error("Test!"))).toEqual({
...defaults.bookmark,
error: "Test!",
});
expect(handleError("searchProvider", Error("Test!"))).toEqual({
...defaults.search,
error: "Test!",
});
expect(handleError("theme", Error("Test!"))).toEqual({
...defaults.theme,
error: "Test!",
});
expect(handleError("imprint", Error("Test!"))).toEqual({
...defaults.imprint,
error: "Test!",
});
expect(handleError("greeter", Error("Test!"))).toEqual({
...defaults.greeter,
error: "Test!",
});
expect(handleError("", Error("Test!"))).toEqual(undefined);
});
});

View file

@ -1,8 +1,4 @@
import selectedTheme, { import { getTheme, IThemeProps, setTheme } from "../../lib/theme";
getTheme,
IThemeProps,
setTheme,
} from "../../lib/theme";
const props: IThemeProps = { const props: IThemeProps = {
label: "Classic", label: "Classic",
@ -12,33 +8,47 @@ const props: IThemeProps = {
backgroundColor: "#ffffff", backgroundColor: "#ffffff",
}; };
const theme = JSON.stringify(props); const location: Location = window.location;
const setup = () => {
describe("theme.tsx", () => {
beforeEach(() => {
Object.defineProperty(window, "localStorage", { Object.defineProperty(window, "localStorage", {
value: { value: {
getItem: jest.fn(() => null), getItem: jest.fn(() => JSON.stringify(props)),
setItem: jest.fn(() => null), setItem: jest.fn(() => null),
}, },
writable: true, writable: true,
}); });
});
// @ts-ignore
delete window.location;
window.location = {
...location,
reload: jest.fn(),
};
};
describe("theme.tsx", () => {
it("setTheme test", () => { it("setTheme test", () => {
setTheme(theme); setup();
setTheme(props);
expect(window.localStorage.setItem).toHaveBeenCalledTimes(1); expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
expect(window.localStorage.setItem).toHaveBeenCalledWith("theme", theme); expect(window.localStorage.setItem).toHaveBeenCalledWith(
"theme",
JSON.stringify(props),
);
expect(window.location.reload).toHaveBeenCalledTimes(1);
}); });
it("getTheme test", () => { it("Tests getTheme", () => {
const themeTest = getTheme(); setup();
let themeTest = getTheme();
expect(themeTest).toEqual(props); expect(themeTest).toEqual(props);
}); });
it("selectedTheme test", () => { it("Tests getTheme with empty parameters", () => {
const themeTest = selectedTheme; localStorage.setItem("theme", "");
expect(themeTest).toEqual(props); expect(getTheme()).toEqual({});
}); });
}); });