Replace useFetcher with useFetch.

This commit is contained in:
Bastian Meissner 2022-02-13 20:57:26 +01:00
parent d4f593c4ce
commit 942cba97da
15 changed files with 292 additions and 740 deletions

View file

@ -8,7 +8,7 @@ import Settings from "./components/settings";
import Imprint from "./components/imprint"; import Imprint from "./components/imprint";
import { IThemeProps, getTheme, setScheme } from "./lib/useTheme"; import { IThemeProps, getTheme, setScheme } from "./lib/useTheme";
import useFetcher from "./lib/fetcher"; import useFetch from "./lib/useFetch";
import useMediaQuery from "./lib/useMediaQuery"; import useMediaQuery from "./lib/useMediaQuery";
export const GlobalStyle = createGlobalStyle<{ theme: IThemeProps }>` export const GlobalStyle = createGlobalStyle<{ theme: IThemeProps }>`
@ -33,37 +33,29 @@ const App = () => {
const { const {
appData, appData,
bookmarkData, bookmarkData,
searchProviderData, searchData,
themeData, themeData,
imprintData, imprintData,
greeterData, greeterData,
} = useFetcher(); } = useFetch();
const theme = getTheme(); const theme = getTheme();
let isDark = useMediaQuery("(prefers-color-scheme: dark)"); let isDark = useMediaQuery("(prefers-color-scheme: dark)");
if (isDark) { setScheme(isDark ? "dark-theme" : "light-theme");
setScheme("dark-theme");
} else {
setScheme("light-theme");
}
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<GlobalStyle /> <GlobalStyle />
<div> <div>
<SearchBar search={searchProviderData?.search} /> <SearchBar search={searchData.response} />
{(!themeData.error || !searchProviderData.error) && ( <Settings themes={themeData.response} search={searchData.response} />
<Settings <Greeter greeter={greeterData.response} />
themes={themeData?.themes} <AppList
search={searchProviderData?.search} apps={appData.response?.apps}
categories={appData.response?.categories}
/> />
)} <BookmarkList groups={bookmarkData.response?.groups} />
<Greeter data={greeterData.greeter} /> <Imprint imprint={imprintData.response} />
{!appData.error && (
<AppList apps={appData.apps} categories={appData.categories} />
)}
{!bookmarkData.error && <BookmarkList groups={bookmarkData.groups} />}
{!imprintData.error && <Imprint imprint={imprintData.imprint} />}
</div> </div>
</ThemeProvider> </ThemeProvider>
); );

View file

@ -38,7 +38,7 @@ export interface IBookmarkGroupProps {
} }
export interface IBookmarkListProps { export interface IBookmarkListProps {
groups: Array<IBookmarkGroupProps>; groups?: Array<IBookmarkGroupProps>;
} }
export const Bookmark = ({ name, url, newTab }: IBookmarkProps) => { export const Bookmark = ({ name, url, newTab }: IBookmarkProps) => {
@ -83,15 +83,23 @@ export const BookmarkGroup = ({ name, items }: IBookmarkGroupProps) => (
* @param {IBookmarkListProps} props props of the given bookmark list * @param {IBookmarkListProps} props props of the given bookmark list
* @returns {React.ReactNode} the bookmark list component * @returns {React.ReactNode} the bookmark list component
*/ */
const BookmarkList = ({ groups }: IBookmarkListProps) => ( const BookmarkList = ({ groups }: IBookmarkListProps) => {
if (groups === undefined || groups.length <= 0) return <></>;
return (
<ListContainer> <ListContainer>
<Headline>Bookmarks</Headline> <Headline>Bookmarks</Headline>
<ItemList> <ItemList>
{groups.map(({ name, items }, index) => ( {groups.map(({ name, items }, index) => (
<BookmarkGroup key={[name, index].join("")} name={name} items={items} /> <BookmarkGroup
key={[name, index].join("")}
name={name}
items={items}
/>
))} ))}
</ItemList> </ItemList>
</ListContainer> </ListContainer>
); );
};
export default BookmarkList; export default BookmarkList;

View file

@ -20,7 +20,11 @@ const DateText = styled.h3`
`; `;
export interface IGreeterComponentProps { export interface IGreeterComponentProps {
data: IGreeterProps; greeter?: IGreeterDataProps;
}
export interface IGreeterDataProps {
greeter: IGreeterProps;
} }
export interface IGreeterProps { export interface IGreeterProps {
@ -114,13 +118,21 @@ export const getDateString = (
* @param {IGreeterComponentProps} data required greeter data * @param {IGreeterComponentProps} data required greeter data
* @returns {React.ReactNode} the greeter * @returns {React.ReactNode} the greeter
*/ */
const Greeter = ({ data }: IGreeterComponentProps) => ( const Greeter = ({ greeter }: IGreeterComponentProps) => {
if (greeter === undefined) return <></>;
return (
<GreeterContainer> <GreeterContainer>
<DateText> <DateText>
{getDateString(data.days, data.months, data.dateformat)} {getDateString(
greeter.greeter.days,
greeter.greeter.months,
greeter.greeter.dateformat,
)}
</DateText> </DateText>
<GreetText>{getGreeting(data.greetings)}</GreetText> <GreetText>{getGreeting(greeter.greeter.greetings)}</GreetText>
</GreeterContainer> </GreeterContainer>
); );
};
export default Greeter; export default Greeter;

View file

@ -40,7 +40,7 @@ export interface IImprintProps {
} }
export interface IImprintComponentProps { export interface IImprintComponentProps {
imprint: IImprintProps; imprint?: IImprintProps;
} }
interface IImprintFieldComponentProps { interface IImprintFieldComponentProps {
@ -72,7 +72,10 @@ export const onClose = () => {
* @param {IImprintProps} props contents of the imprint * @param {IImprintProps} props contents of the imprint
* @returns {React.ReactNode} the imprint node * @returns {React.ReactNode} the imprint node
*/ */
const Imprint = ({ imprint }: IImprintComponentProps) => ( const Imprint = ({ imprint }: IImprintComponentProps) => {
if (imprint === undefined) return <></>;
return (
<> <>
<ListContainer> <ListContainer>
<Headline>About</Headline> <Headline>About</Headline>
@ -107,6 +110,7 @@ const Imprint = ({ imprint }: IImprintComponentProps) => (
</ItemList> </ItemList>
</ListContainer> </ListContainer>
</> </>
); );
};
export default Imprint; export default Imprint;

View file

@ -48,7 +48,7 @@ export interface ISearchProps {
} }
interface ISearchBarProps { interface ISearchBarProps {
search: ISearchProps; search?: ISearchProps;
} }
export const handleQueryWithProvider = ( export const handleQueryWithProvider = (
@ -85,6 +85,8 @@ const SearchBar = ({ search }: ISearchBarProps) => {
useEffect(() => setButtonsHidden(input === ""), [input]); useEffect(() => setButtonsHidden(input === ""), [input]);
if (search === undefined) return <></>;
const handleSearchQuery = (e: React.FormEvent) => { const handleSearchQuery = (e: React.FormEvent) => {
var query: string = input || ""; var query: string = input || "";

View file

@ -46,9 +46,7 @@ const Select = ({
className={className} className={className}
value={selected} value={selected}
> >
{items.map(({ label, value }, index) => { {items.map(({ label, value }, index) => (
if (label === current) {
return (
<option <option
data-testid={"option-" + (testId ? `${testId}-` : "") + index} data-testid={"option-" + (testId ? `${testId}-` : "") + index}
key={[label, index].join("")} key={[label, index].join("")}
@ -56,19 +54,7 @@ const Select = ({
> >
{label} {label}
</option> </option>
); ))}
} else {
return (
<option
data-testid={"option-" + (testId ? `${testId}-` : "") + index}
key={[label, index].join("")}
value={value.toString()}
>
{label}
</option>
);
}
})}
</List> </List>
); );
}; };

View file

@ -4,7 +4,12 @@ import styled from "styled-components";
import Select from "./select"; import Select from "./select";
import { ISearchProps } from "./searchBar"; import { ISearchProps } from "./searchBar";
import { setTheme, IThemeProps, getTheme } from "../lib/useTheme"; import {
setTheme,
IThemeProps,
IThemeDataProps,
getTheme,
} from "../lib/useTheme";
import { Button, SubHeadline } from "./elements"; import { Button, SubHeadline } from "./elements";
import Modal from "./modal"; import Modal from "./modal";
@ -88,13 +93,13 @@ const ContentContainer = styled.div`
`; `;
interface ISettingsProps { interface ISettingsProps {
themes: Array<IThemeProps> | undefined; themes?: IThemeDataProps;
search: ISearchProps | undefined; search?: ISearchProps;
} }
/** /**
* Handles the settings-modal * Handles the settings-modal
* @param {Array<IThemeProps>} themes - the list of themes a user can select between * @param {IThemeDataProps} themes - the list of themes a user can select between
* @param {ISearchProps} search - the list of search providers * @param {ISearchProps} search - the list of search providers
*/ */
const Settings = ({ themes, search }: ISettingsProps) => { const Settings = ({ themes, search }: ISettingsProps) => {
@ -104,18 +109,19 @@ const Settings = ({ themes, search }: ISettingsProps) => {
const currentLightTheme = getTheme("light").value; const currentLightTheme = getTheme("light").value;
const currentDarkTheme = getTheme("dark").value; const currentDarkTheme = getTheme("dark").value;
if (themes || search) { if (themes === undefined && search === undefined) return <></>;
return ( return (
<Modal element="icon" icon="settings" title="Settings"> <Modal element="icon" icon="settings" title="Settings">
<ContentContainer> <ContentContainer>
{themes && ( {themes !== undefined && (
<Section> <Section>
<SectionHeadline>Theme</SectionHeadline> <SectionHeadline>Theme</SectionHeadline>
<FormContainer> <FormContainer>
<div> <div>
<ThemeHeader>Light</ThemeHeader> <ThemeHeader>Light</ThemeHeader>
<ThemeSelect <ThemeSelect
items={themes} items={themes.themes}
onChange={(theme: IThemeProps) => setNewLightTheme(theme)} onChange={(theme: IThemeProps) => setNewLightTheme(theme)}
current={currentLightTheme} current={currentLightTheme}
testId="light" testId="light"
@ -124,7 +130,7 @@ const Settings = ({ themes, search }: ISettingsProps) => {
<div> <div>
<ThemeHeader>Dark</ThemeHeader> <ThemeHeader>Dark</ThemeHeader>
<ThemeSelect <ThemeSelect
items={themes} items={themes.themes}
onChange={(theme: IThemeProps) => setNewDarkTheme(theme)} onChange={(theme: IThemeProps) => setNewDarkTheme(theme)}
current={currentDarkTheme} current={currentDarkTheme}
testId="dark" testId="dark"
@ -152,7 +158,7 @@ const Settings = ({ themes, search }: ISettingsProps) => {
</FormContainer> </FormContainer>
</Section> </Section>
)} )}
{search && ( {search !== undefined && (
<Section> <Section>
<SectionHeadline>Search Providers</SectionHeadline> <SectionHeadline>Search Providers</SectionHeadline>
<> <>
@ -182,9 +188,6 @@ const Settings = ({ themes, search }: ISettingsProps) => {
</ContentContainer> </ContentContainer>
</Modal> </Modal>
); );
} else {
return <></>;
}
}; };
export default Settings; export default Settings;

31
src/lib/fetch.d.ts vendored
View file

@ -1,31 +0,0 @@
import { ISearchProps } from "../components/searchBar";
import { IBookmarkGroupProps } from "../components/bookmarks";
import { IAppProps, IAppCategoryProps } from "../components/apps";
import { IThemeProps } from "./theme";
import { IImprintProps } from "../components/imprint";
import { IGreeterProps } from "../components/greeter";
declare module "../data/apps.json" {
export const categories: IAppCategoryProps[];
export const apps: IAppProps[];
}
declare module "../data/search.json" {
export const search: ISearchProps;
}
declare module "../data/bookmarks.json" {
export const groups: IBookmarkGroupProps[];
}
declare module "../data/themes.json" {
export const themes: IThemeProps[];
}
declare module "../data/imprint.json" {
export const imprint: IImprintProps;
}
declare module "../data/greeter.json" {
export const greeter: IGreeterProps;
}

View file

@ -1,91 +0,0 @@
import React, { useCallback, useEffect, useState } from "react";
import { IAppListProps } from "../components/apps";
import { IThemeProps } from "./useTheme";
import { IBookmarkListProps } from "../components/bookmarks";
import { ISearchProps } from "../components/searchBar";
import { IImprintProps } from "../components/imprint";
import { IGreeterProps } from "../components/greeter";
const inProduction = process.env.NODE_ENV === "production";
interface IFetchItemProps {
url: string;
setHook?: React.Dispatch<React.SetStateAction<any>>;
}
interface IFetchListProps {
app: IFetchItemProps;
bookmarks: IFetchItemProps;
greeter: IFetchItemProps;
imprint: IFetchItemProps;
search: IFetchItemProps;
themes: IFetchItemProps;
}
let fetchList: IFetchListProps = {
app: { url: "/data/app.json" },
bookmarks: { url: "/data/bookmarks.json" },
greeter: { url: "/data/greeter.json" },
imprint: { url: "/data/imprint.json" },
search: { url: "/data/search.json" },
themes: { url: "/data/themes.json" },
};
export const handleResponse = (response: Response, type: string) => {
if (response.ok) return response.json();
throw new Error("Error fetching " + type + " data");
};
const handleError = (error: Error) => {
console.error(error.message);
};
const fetchURL = (url: string, type: string) => {
const response = inProduction ? fetch(url) : import(".." + url);
return response
.then((response: Response) => handleResponse(response, type))
.catch(handleError);
};
const useFetch = () => {
const [appData, setAppData] = useState<IAppListProps>();
fetchList.app.setHook = setAppData;
const [bookmarkData, setBookmarkData] = useState<IBookmarkListProps>();
fetchList.bookmarks.setHook = setBookmarkData;
const [greeterData, setGreeterData] = useState<IGreeterProps>();
fetchList.greeter.setHook = setGreeterData;
const [imprintData, setImprintData] = useState<IImprintProps>();
fetchList.imprint.setHook = setImprintData;
const [searchData, setSearchData] = useState<ISearchProps>();
fetchList.search.setHook = setSearchData;
const [themeData, setThemeData] = useState<Array<IThemeProps>>();
fetchList.themes.setHook = setThemeData;
const callback = useCallback(() => {
Object.entries(fetchList).forEach(([key, val]) => {
fetchURL(val.url, key).then((data) => {
val.setHook(data);
});
});
}, []);
useEffect(() => callback(), [callback]);
return {
appData,
bookmarkData,
greeterData,
imprintData,
searchData,
themeData,
callback,
};
};
export default useFetch;

32
src/lib/fetcher.d.ts vendored
View file

@ -1,32 +0,0 @@
import { ISearchProps } from "../components/searchBar";
import { IBookmarkGroupProps } from "../components/bookmarks";
import { IAppCategoryProps } from "../components/appCategory";
import { IAppProps } from "../components/app";
import { IThemeProps } from "./theme";
import { IImprintProps } from "../components/imprint";
import { IGreeterProps } from "../components/greeter";
declare module "../data/apps.json" {
export const categories: IAppCategoryProps[];
export const apps: IAppProps[];
}
declare module "../data/search.json" {
export const search: ISearchProps;
}
declare module "../data/bookmarks.json" {
export const groups: IBookmarkGroupProps[];
}
declare module "../data/themes.json" {
export const themes: IThemeProps[];
}
declare module "../data/imprint.json" {
export const imprint: IImprintProps;
}
declare module "../data/greeter.json" {
export const greeter: IGreeterProps;
}

View file

@ -1,278 +0,0 @@
import { useCallback, useEffect, useState } from "react";
import { ISearchProps } from "../components/searchBar";
import { IBookmarkGroupProps } from "../components/bookmarks";
import { IAppCategoryProps } from "../components/appCategory";
import { IAppProps } from "../components/app";
import { IThemeProps } from "./useTheme";
import { IImprintProps } from "../components/imprint";
import { IGreeterProps } from "../components/greeter";
const errorMessage = "Failed to load data.";
const inProduction = process.env.NODE_ENV === "production";
/**
* Handles the response from the fetch requests
* @param {Response} response - The response given by the fetch request
* @returns - The response in JSON
* @throws - Error with given error message if request failed
*/
export const handleResponse = (response: Response) => {
if (response.ok) return response.json();
throw new Error(errorMessage);
};
export interface ISearchDataProps {
search: ISearchProps;
error: string | boolean;
}
export interface IBookmarkDataProps {
groups: Array<IBookmarkGroupProps>;
error: string | boolean;
}
export interface IAppDataProps {
categories: Array<IAppCategoryProps>;
apps: Array<IAppProps>;
error: string | boolean;
}
export interface IThemeDataProps {
themes: Array<IThemeProps>;
error: string | boolean;
}
export interface IImprintDataProps {
imprint: IImprintProps;
error: string | boolean;
}
export interface IGreeterDataProps {
greeter: IGreeterProps;
error: string | boolean;
}
/**
* Default values for the respective state variables
*/
export const defaults = {
app: {
categories: [],
apps: [],
error: false,
},
bookmark: {
groups: [],
error: false,
},
search: {
search: {
placeholder: "",
defaultProvider: "https://google.com/search?q=",
providers: [],
},
error: false,
},
theme: {
themes: [],
error: false,
},
imprint: {
imprint: {
name: { text: "", link: "" },
address: { text: "", link: "" },
phone: { text: "", link: "" },
email: { text: "", link: "" },
url: { text: "", link: "" },
text: "",
},
error: false,
},
greeter: {
greeter: {
months: [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
],
days: [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
],
greetings: [
{
greeting: "Good night!",
start: 0,
end: 6,
},
{
greeting: "Good morning!",
start: 6,
end: 12,
},
{
greeting: "Good afternoon!",
start: 12,
end: 18,
},
{
greeting: "Good evening!",
start: 18,
end: 0,
},
],
dateformat: "%wd, %m %d%e %y",
},
error: false,
},
};
/**
* Handles fetch errors by returning the error message.
* @param {string} type - The type of fetch request that threw an error
* @param {Error} error - The error itself
*/
export const handleError = (status: string, error: Error) => {
switch (status) {
case "apps":
return { ...defaults.app, error: error.message };
case "bookmark":
return { ...defaults.bookmark, error: error.message };
case "searchProvider":
return { ...defaults.search, error: error.message };
case "theme":
return { ...defaults.theme, error: error.message };
case "imprint":
return { ...defaults.imprint, error: error.message };
case "greeter":
return { ...defaults.greeter, error: error.message };
default:
break;
}
};
/**
* Fetches all of the data by doing fetch requests (only available in production)
*/
export const fetchProduction = Promise.all([
fetch("/data/apps.json")
.then(handleResponse)
.catch((error: Error) => handleError("apps", error)),
fetch("/data/bookmarks.json")
.then(handleResponse)
.catch((error: Error) => handleError("bookmark", error)),
fetch("/data/search.json")
.then(handleResponse)
.catch((error: Error) => handleError("searchProvider", error)),
fetch("/data/themes.json")
.then(handleResponse)
.catch((error: Error) => handleError("theme", error)),
fetch("/data/imprint.json")
.then(handleResponse)
.catch((error: Error) => handleError("imprint", error)),
fetch("/data/greeter.json")
.then(handleResponse)
.catch((error: Error) => handleError("greeter", error)),
]);
/**
* Fetches all of the data by importing it (only available in development)
*/
export const fetchDevelopment = Promise.all([
import("../data/apps.json"),
import("../data/bookmarks.json"),
import("../data/search.json"),
import("../data/themes.json"),
import("../data/imprint.json"),
import("../data/greeter.json"),
]);
/**
* Fetches app, bookmark, search, theme and imprint data and returns it.
*/
export const useFetcher = () => {
const [appData, setAppData] = useState<IAppDataProps>(defaults.app);
const [bookmarkData, setBookmarkData] = useState<IBookmarkDataProps>(
defaults.bookmark,
);
const [searchProviderData, setSearchProviderData] =
useState<ISearchDataProps>(defaults.search);
const [themeData, setThemeData] = useState<IThemeDataProps>(defaults.theme);
const [imprintData, setImprintData] = useState<IImprintDataProps>(
defaults.imprint,
);
const [greeterData, setGreeterData] = useState<IGreeterDataProps>(
defaults.greeter,
);
const callback = useCallback(() => {
(inProduction ? fetchProduction : fetchDevelopment).then(
([
appData,
bookmarkData,
searchData,
themeData,
imprintData,
greeterData,
]: [
IAppDataProps,
IBookmarkDataProps,
ISearchDataProps,
IThemeDataProps,
IImprintDataProps,
IGreeterDataProps,
]) => {
setAppData(appData.error ? appData : { ...appData, error: false });
setBookmarkData(
bookmarkData.error ? bookmarkData : { ...bookmarkData, error: false },
);
setSearchProviderData(
searchData.error ? searchData : { ...searchData, error: false },
);
setThemeData(
themeData.error ? themeData : { ...themeData, error: false },
);
setImprintData(
imprintData.error ? imprintData : { ...imprintData, error: false },
);
setGreeterData(
greeterData.error ? greeterData : { ...greeterData, error: false },
);
},
);
}, []);
useEffect(() => callback(), [callback]);
return {
appData,
bookmarkData,
searchProviderData,
themeData,
imprintData,
greeterData,
callback,
};
};
export default useFetcher;

95
src/lib/useFetch.tsx Normal file
View file

@ -0,0 +1,95 @@
import { useCallback, useEffect, useState } from "react";
import { IAppListProps } from "../components/appList";
import { IBookmarkListProps } from "../components/bookmarks";
import { ISearchProps } from "../components/searchBar";
import { IThemeDataProps } from "./useTheme";
import { IImprintProps } from "../components/imprint";
import { IGreeterDataProps } from "../components/greeter";
export interface IDataProps<I> {
response?: I;
error?: string | boolean;
}
const inProduction = process.env.NODE_ENV === "production";
/**
* Handles the response from the fetch requests
* @param {Response} response - The response given by the fetch request
* @returns - The response in JSON
* @throws - Error with given error message if request failed
*/
export const handleResponse = async (response: Response) => {
if (!response.ok) throw new Error(response.statusText);
return response.json();
};
const fetchFile = (f: string) => {
if (!inProduction) return require(`../data/${f}.json`);
return fetch(`/data/${f}.json`)
.then(handleResponse)
.catch((error: Error) => {
return { error: error.message };
});
};
interface IFetchProps {
appData: IDataProps<IAppListProps>;
bookmarkData: IDataProps<IBookmarkListProps>;
searchData: IDataProps<ISearchProps>;
themeData: IDataProps<IThemeDataProps>;
imprintData: IDataProps<IImprintProps>;
greeterData: IDataProps<IGreeterDataProps>;
callback?: () => void;
}
/**
* Fetches app, bookmark, search, theme and imprint data and returns it.
*/
export const useFetcher = (): IFetchProps => {
let defaults: IDataProps<any> = { error: true };
const [appData, setAppData] = useState<IDataProps<IAppListProps>>(defaults);
const [bookmarkData, setBookmarkData] =
useState<IDataProps<IBookmarkListProps>>(defaults);
const [searchData, setSearchData] =
useState<IDataProps<ISearchProps>>(defaults);
const [themeData, setThemeData] =
useState<IDataProps<IThemeDataProps>>(defaults);
const [imprintData, setImprintData] =
useState<IDataProps<IImprintProps>>(defaults);
const [greeterData, setGreeterData] =
useState<IDataProps<IGreeterDataProps>>(defaults);
const callback = useCallback(() => {
let files = ["apps", "bookmarks", "search", "themes", "imprint", "greeter"];
Promise.all(files.map((f) => fetchFile(f))).then(
([apps, bookmarks, search, themes, imprint, greeter]: any) => {
setAppData({ response: apps });
setBookmarkData({
response: bookmarks,
});
setSearchData({ response: search });
setThemeData({ response: themes });
setImprintData({ response: imprint });
setGreeterData({ response: greeter });
},
);
}, []);
useEffect(() => callback(), [callback]);
return {
appData,
bookmarkData,
searchData,
themeData,
imprintData,
greeterData,
};
};
export default useFetcher;

View file

@ -6,6 +6,10 @@ export interface IThemeProps extends IItemProps {
backgroundColor: string; backgroundColor: string;
} }
export interface IThemeDataProps {
themes: IThemeProps[];
}
export const defaultTheme: IThemeProps = { export const defaultTheme: IThemeProps = {
label: "Classic", label: "Classic",
value: 0, value: 0,

View file

@ -1,46 +0,0 @@
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,76 +0,0 @@
import { getTheme, IThemeProps, setScheme, setTheme } from "../../lib/useTheme";
const props: IThemeProps = {
label: "Classic",
value: 0,
mainColor: "#000000",
accentColor: "#1e272e",
backgroundColor: "#ffffff",
};
const location: Location = window.location;
const setup = () => {
Object.defineProperty(window, "localStorage", {
value: {
getItem: jest.fn(() => JSON.stringify(props)),
setItem: jest.fn(() => null),
},
writable: true,
});
// @ts-ignore
delete window.location;
window.location = {
...location,
reload: jest.fn(),
};
};
describe("theme.tsx", () => {
it("Tests setScheme", () => {
setup();
let value = "dark";
setScheme(value);
expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
expect(window.localStorage.setItem).toHaveBeenCalledWith("theme", value);
});
it("setTheme light test", () => {
setup();
setTheme("light", props);
expect(window.localStorage.setItem).toHaveBeenCalledTimes(2);
expect(window.localStorage.setItem).toHaveBeenCalledWith(
"light-theme",
JSON.stringify(props),
);
expect(window.location.reload).toHaveBeenCalledTimes(1);
});
it("setTheme dark test", () => {
setup();
setTheme("dark", props);
expect(window.localStorage.setItem).toHaveBeenCalledTimes(2);
expect(window.localStorage.setItem).toHaveBeenCalledWith(
"dark-theme",
JSON.stringify(props),
);
expect(window.location.reload).toHaveBeenCalledTimes(1);
});
it("Tests getTheme", () => {
setup();
let themeTest = getTheme();
expect(themeTest).toEqual(props);
});
it("Tests getTheme with empty parameters", () => {
localStorage.setItem("theme", "");
expect(getTheme()).toEqual({});
});
});