diff --git a/shlink-web-component/src/index.ts b/shlink-web-component/src/index.ts
index 875ec5d2..56081ea7 100644
--- a/shlink-web-component/src/index.ts
+++ b/shlink-web-component/src/index.ts
@@ -3,4 +3,14 @@ import { createShlinkWebComponent } from './ShlinkWebComponent';
export const ShlinkWebComponent = createShlinkWebComponent(bottle);
-export type { Settings } from './utils/settings';
+export type ShlinkWebComponentType = typeof ShlinkWebComponent;
+
+export type {
+ RealTimeUpdatesSettings,
+ ShortUrlCreationSettings,
+ ShortUrlsListSettings,
+ UiSettings,
+ VisitsSettings,
+ TagsSettings,
+ Settings,
+} from './utils/settings';
diff --git a/test/common/SimplePaginator.test.tsx b/shlink-web-component/test/utils/components/SimplePaginator.test.tsx
similarity index 89%
rename from test/common/SimplePaginator.test.tsx
rename to shlink-web-component/test/utils/components/SimplePaginator.test.tsx
index 0f29e9d3..b3557603 100644
--- a/test/common/SimplePaginator.test.tsx
+++ b/shlink-web-component/test/utils/components/SimplePaginator.test.tsx
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
-import { SimplePaginator } from '../../shlink-web-component/src/utils/components/SimplePaginator';
-import { ELLIPSIS } from '../../shlink-web-component/src/utils/helpers/pagination';
+import { SimplePaginator } from '../../../src/utils/components/SimplePaginator';
+import { ELLIPSIS } from '../../../src/utils/helpers/pagination';
describe('', () => {
const setUp = (pagesCount: number, currentPage = 1) => render(
diff --git a/src/api/services/ShlinkApiClient.ts b/src/api/services/ShlinkApiClient.ts
index 3ac8148c..58c54699 100644
--- a/src/api/services/ShlinkApiClient.ts
+++ b/src/api/services/ShlinkApiClient.ts
@@ -109,7 +109,7 @@ export class ShlinkApiClient implements BaseShlinkApiClient {
.then(({ data }) => ({ tags: data.map(({ tag }) => tag), stats: data }));
public readonly deleteTags = async (tags: string[]): Promise<{ tags: string[] }> =>
- this.performEmptyRequest({ url: '/tags', method: 'DELETE', body: { tags } }).then(() => ({ tags }));
+ this.performEmptyRequest({ url: '/tags', method: 'DELETE', query: { tags } }).then(() => ({ tags }));
public readonly editTag = async (oldName: string, newName: string): Promise<{ oldName: string; newName: string }> =>
this.performEmptyRequest({
diff --git a/src/app/App.tsx b/src/app/App.tsx
index 16468ad1..becfe1d7 100644
--- a/src/app/App.tsx
+++ b/src/app/App.tsx
@@ -21,7 +21,7 @@ interface AppProps {
export const App = (
MainHeader: FC,
Home: FC,
- MenuLayout: FC,
+ ShlinkWebComponentContainer: FC,
CreateServer: FC,
EditServer: FC,
SettingsComp: FC,
@@ -52,7 +52,7 @@ export const App = (
} />
} />
} />
- } />
+ } />
} />
diff --git a/src/app/services/provideServices.ts b/src/app/services/provideServices.ts
index a73d7c83..3ef5cd72 100644
--- a/src/app/services/provideServices.ts
+++ b/src/app/services/provideServices.ts
@@ -10,7 +10,7 @@ export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
App,
'MainHeader',
'Home',
- 'MenuLayout',
+ 'ShlinkWebComponentContainer',
'CreateServer',
'EditServer',
'Settings',
diff --git a/src/common/MenuLayout.scss b/src/common/ShlinkWebComponentContainer.scss
similarity index 100%
rename from src/common/MenuLayout.scss
rename to src/common/ShlinkWebComponentContainer.scss
diff --git a/src/common/MenuLayout.tsx b/src/common/ShlinkWebComponentContainer.tsx
similarity index 59%
rename from src/common/MenuLayout.tsx
rename to src/common/ShlinkWebComponentContainer.tsx
index 4661dc2f..20f62a9f 100644
--- a/src/common/MenuLayout.tsx
+++ b/src/common/ShlinkWebComponentContainer.tsx
@@ -1,33 +1,34 @@
import type { FC } from 'react';
import { useEffect } from 'react';
-import type { Settings } from '../../shlink-web-component/src';
-import { ShlinkWebComponent } from '../../shlink-web-component/src';
+import type { Settings, ShlinkWebComponentType } from '../../shlink-web-component/src';
import type { ShlinkApiClientBuilder } from '../api/services/ShlinkApiClientBuilder';
import { isReachableServer } from '../servers/data';
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
import { NotFound } from './NotFound';
-import './MenuLayout.scss';
+import './ShlinkWebComponentContainer.scss';
-interface MenuLayoutProps {
+interface ShlinkWebComponentContainerProps {
sidebarPresent: Function;
sidebarNotPresent: Function;
settings: Settings;
}
-// FIXME Rename this to something else
-export const MenuLayout = (
+export const ShlinkWebComponentContainer = (
buildShlinkApiClient: ShlinkApiClientBuilder,
+ ShlinkWebComponent: ShlinkWebComponentType,
ServerError: FC,
-) => withSelectedServer(({ selectedServer, sidebarNotPresent, sidebarPresent, settings }) => {
- const showContent = isReachableServer(selectedServer);
- const routesPrefix = showContent ? `/server/${selectedServer.id}` : '';
+) => withSelectedServer((
+ { selectedServer, sidebarNotPresent, sidebarPresent, settings },
+) => {
+ const selectedServerIsReachable = isReachableServer(selectedServer);
+ const routesPrefix = selectedServerIsReachable ? `/server/${selectedServer.id}` : '';
useEffect(() => {
- showContent && sidebarPresent();
+ selectedServerIsReachable && sidebarPresent();
return () => sidebarNotPresent();
}, []);
- if (!showContent) {
+ if (!selectedServerIsReachable) {
return ;
}
diff --git a/src/common/reducers/sidebar.ts b/src/common/reducers/sidebar.ts
index e94bbd52..eedee0cb 100644
--- a/src/common/reducers/sidebar.ts
+++ b/src/common/reducers/sidebar.ts
@@ -1,8 +1,8 @@
import { createSlice } from '@reduxjs/toolkit';
-// TODO This is only used for some components to have extra paddings/styles if existing section has a side menu
-// Now that's basically the route which renders ShlinkWebComponent, so maybe there's some way to re-think this
-// logic, and perhaps get rid of a reducer just for that
+// FIXME This is only used for some components to have extra paddings/styles if existing section has a side menu
+// Now that's basically the route which renders ShlinkWebComponent, so maybe there's some way to re-think this
+// logic, and perhaps get rid of a reducer just for that
export interface Sidebar {
sidebarPresent: boolean;
diff --git a/src/common/services/provideServices.ts b/src/common/services/provideServices.ts
index 1c6be10d..bca33c67 100644
--- a/src/common/services/provideServices.ts
+++ b/src/common/services/provideServices.ts
@@ -1,13 +1,14 @@
import type Bottle from 'bottlejs';
+import { ShlinkWebComponent } from '../../../shlink-web-component/src';
import type { ConnectDecorator } from '../../container/types';
import { withoutSelectedServer } from '../../servers/helpers/withoutSelectedServer';
import { ErrorHandler } from '../ErrorHandler';
import { Home } from '../Home';
import { MainHeader } from '../MainHeader';
-import { MenuLayout } from '../MenuLayout';
import { sidebarNotPresent, sidebarPresent } from '../reducers/sidebar';
import { ScrollToTop } from '../ScrollToTop';
import { ShlinkVersionsContainer } from '../ShlinkVersionsContainer';
+import { ShlinkWebComponentContainer } from '../ShlinkWebComponentContainer';
import { HttpClient } from './HttpClient';
export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
@@ -26,8 +27,15 @@ export const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.decorator('Home', withoutSelectedServer);
bottle.decorator('Home', connect(['servers'], ['resetSelectedServer']));
- bottle.serviceFactory('MenuLayout', MenuLayout, 'buildShlinkApiClient', 'ServerError');
- bottle.decorator('MenuLayout', connect(
+ bottle.serviceFactory('ShlinkWebComponent', () => ShlinkWebComponent);
+ bottle.serviceFactory(
+ 'ShlinkWebComponentContainer',
+ ShlinkWebComponentContainer,
+ 'buildShlinkApiClient',
+ 'ShlinkWebComponent',
+ 'ServerError',
+ );
+ bottle.decorator('ShlinkWebComponentContainer', connect(
['selectedServer', 'settings'],
['selectServer', 'sidebarPresent', 'sidebarNotPresent'],
));
diff --git a/src/settings/ShortUrlCreationSettings.tsx b/src/settings/ShortUrlCreationSettings.tsx
index bb0c17d8..e7ff56ec 100644
--- a/src/settings/ShortUrlCreationSettings.tsx
+++ b/src/settings/ShortUrlCreationSettings.tsx
@@ -1,11 +1,10 @@
import type { FC, ReactNode } from 'react';
import { DropdownItem, FormGroup } from 'reactstrap';
import { DropdownBtn, LabeledFormGroup, SimpleCard, ToggleSwitch } from '../../shlink-frontend-kit/src';
-import type { Settings } from '../../shlink-web-component/src';
+import type { Settings, ShortUrlCreationSettings as ShortUrlsSettings } from '../../shlink-web-component/src';
import { FormText } from '../utils/forms/FormText';
import type { Defined } from '../utils/types';
-type ShortUrlsSettings = Defined;
type TagFilteringMode = Defined;
interface ShortUrlCreationProps {
diff --git a/src/settings/ShortUrlsListSettings.tsx b/src/settings/ShortUrlsListSettings.tsx
index 686c39f8..05664572 100644
--- a/src/settings/ShortUrlsListSettings.tsx
+++ b/src/settings/ShortUrlsListSettings.tsx
@@ -1,12 +1,9 @@
import type { FC } from 'react';
import { LabeledFormGroup, OrderingDropdown, SimpleCard } from '../../shlink-frontend-kit/src';
-import type { Settings } from '../../shlink-web-component/src';
+import type { Settings, ShortUrlsListSettings as ShortUrlsSettings } from '../../shlink-web-component/src';
import { SHORT_URLS_ORDERABLE_FIELDS } from '../../shlink-web-component/src/short-urls/data';
-import type { Defined } from '../utils/types';
import { DEFAULT_SHORT_URLS_ORDERING } from './reducers/settings';
-type ShortUrlsSettings = Defined;
-
interface ShortUrlsListSettingsProps {
settings: Settings;
setShortUrlsListSettings: (settings: ShortUrlsSettings) => void;
diff --git a/src/settings/TagsSettings.tsx b/src/settings/TagsSettings.tsx
index f1ffd3ae..b1f4e321 100644
--- a/src/settings/TagsSettings.tsx
+++ b/src/settings/TagsSettings.tsx
@@ -1,10 +1,7 @@
import type { FC } from 'react';
import { LabeledFormGroup, OrderingDropdown, SimpleCard } from '../../shlink-frontend-kit/src';
-import type { Settings } from '../../shlink-web-component/src';
+import type { Settings, TagsSettings as TagsSettingsOptions } from '../../shlink-web-component/src';
import { TAGS_ORDERABLE_FIELDS } from '../../shlink-web-component/src/tags/data/TagsListChildrenProps';
-import type { Defined } from '../utils/types';
-
-type TagsSettingsOptions = Defined;
interface TagsProps {
settings: Settings;
diff --git a/src/settings/UserInterfaceSettings.tsx b/src/settings/UserInterfaceSettings.tsx
index 547f70f6..82c970b1 100644
--- a/src/settings/UserInterfaceSettings.tsx
+++ b/src/settings/UserInterfaceSettings.tsx
@@ -2,14 +2,11 @@ import { faMoon, faSun } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import type { FC } from 'react';
import { SimpleCard, ToggleSwitch } from '../../shlink-frontend-kit/src';
-import type { Settings } from '../../shlink-web-component/src';
+import type { Settings, UiSettings } from '../../shlink-web-component/src';
import type { Theme } from '../utils/theme';
import { changeThemeInMarkup } from '../utils/theme';
-import type { Defined } from '../utils/types';
import './UserInterfaceSettings.scss';
-type UiSettings = Defined;
-
interface UserInterfaceProps {
settings: Settings;
setUiSettings: (settings: UiSettings) => void;
diff --git a/src/settings/VisitsSettings.tsx b/src/settings/VisitsSettings.tsx
index fe71a739..c938958d 100644
--- a/src/settings/VisitsSettings.tsx
+++ b/src/settings/VisitsSettings.tsx
@@ -1,13 +1,11 @@
import type { FC } from 'react';
import { FormGroup } from 'reactstrap';
import { LabeledFormGroup, SimpleCard, ToggleSwitch } from '../../shlink-frontend-kit/src';
-import type { Settings } from '../../shlink-web-component/src';
+import type { Settings, VisitsSettings as VisitsSettingsConfig } from '../../shlink-web-component/src';
import type { DateInterval } from '../../shlink-web-component/src/utils/dates/helpers/dateIntervals';
import { DateIntervalSelector } from '../utils/dates/DateIntervalSelector';
import { FormText } from '../utils/forms/FormText';
-type VisitsSettingsConfig = Settings['visits'];
-
interface VisitsProps {
settings: Settings;
setVisitsSettings: (settings: VisitsSettingsConfig) => void;
diff --git a/src/settings/reducers/settings.ts b/src/settings/reducers/settings.ts
index 5dae6a42..9468ac33 100644
--- a/src/settings/reducers/settings.ts
+++ b/src/settings/reducers/settings.ts
@@ -1,10 +1,15 @@
import type { PayloadAction, PrepareAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { mergeDeepRight } from 'ramda';
-import type { Settings } from '../../../shlink-web-component/src';
+import type {
+ Settings,
+ ShortUrlCreationSettings,
+ ShortUrlsListSettings,
+ TagsSettings,
+ UiSettings, VisitsSettings } from '../../../shlink-web-component/src';
import type { Defined } from '../../utils/types';
-type ShortUrlsOrder = Defined['defaultOrdering']>;
+type ShortUrlsOrder = Defined;
export const DEFAULT_SHORT_URLS_ORDERING: ShortUrlsOrder = {
field: 'dateCreated',
@@ -43,14 +48,14 @@ const { reducer, actions } = createSlice({
toggleRealTimeUpdates: toReducer((enabled: boolean) => toPreparedAction({ realTimeUpdates: { enabled } })),
setRealTimeUpdatesInterval: toReducer((interval: number) => toPreparedAction({ realTimeUpdates: { interval } })),
setShortUrlCreationSettings: toReducer(
- (shortUrlCreation: Settings['shortUrlCreation']) => toPreparedAction({ shortUrlCreation }),
+ (shortUrlCreation: ShortUrlCreationSettings) => toPreparedAction({ shortUrlCreation }),
),
setShortUrlsListSettings: toReducer(
- (shortUrlsList: Settings['shortUrlsList']) => toPreparedAction({ shortUrlsList }),
+ (shortUrlsList: ShortUrlsListSettings) => toPreparedAction({ shortUrlsList }),
),
- setUiSettings: toReducer((ui: Settings['ui']) => toPreparedAction({ ui })),
- setVisitsSettings: toReducer((visits: Settings['visits']) => toPreparedAction({ visits })),
- setTagsSettings: toReducer((tags: Settings['tags']) => toPreparedAction({ tags })),
+ setUiSettings: toReducer((ui: UiSettings) => toPreparedAction({ ui })),
+ setVisitsSettings: toReducer((visits: VisitsSettings) => toPreparedAction({ visits })),
+ setTagsSettings: toReducer((tags: TagsSettings) => toPreparedAction({ tags })),
},
});
diff --git a/src/utils/dates/DateIntervalSelector.tsx b/src/utils/dates/DateIntervalSelector.tsx
index 0e20f8ef..691983bc 100644
--- a/src/utils/dates/DateIntervalSelector.tsx
+++ b/src/utils/dates/DateIntervalSelector.tsx
@@ -1,11 +1,10 @@
import type { FC } from 'react';
import { DropdownItem } from 'reactstrap';
import { DropdownBtn } from '../../../shlink-frontend-kit/src';
-import type { Settings } from '../../../shlink-web-component/src';
+import type { VisitsSettings } from '../../../shlink-web-component/src';
import { rangeOrIntervalToString } from '../../../shlink-web-component/src/utils/dates/helpers/dateIntervals';
-import type { Defined } from '../types';
-export type DateInterval = Defined['defaultInterval'];
+export type DateInterval = VisitsSettings['defaultInterval'];
export interface DateIntervalSelectorProps {
active?: DateInterval;
diff --git a/src/utils/helpers/version.ts b/src/utils/helpers/version.ts
index c75645d9..1d5d708d 100644
--- a/src/utils/helpers/version.ts
+++ b/src/utils/helpers/version.ts
@@ -1,7 +1,7 @@
import { compare } from 'compare-versions';
import { identity, isEmpty, isNil, memoizeWith } from 'ramda';
-type Empty = null | undefined | '' | never[];
+export type Empty = null | undefined | '' | never[];
const hasValue = (value: T | Empty): value is T => !isNil(value) && !isEmpty(value);
@@ -11,7 +11,7 @@ type SemVerPattern = SemVerPatternFragment
| `${SemVerPatternFragment}.${SemVerPatternFragment}`
| `${SemVerPatternFragment}.${SemVerPatternFragment}.${SemVerPatternFragment}`;
-type Versions = {
+export type Versions = {
maxVersion?: SemVerPattern;
minVersion?: SemVerPattern;
};
diff --git a/test/api/services/ShlinkApiClient.test.ts b/test/api/services/ShlinkApiClient.test.ts
index 84fc3eb7..78850ea3 100644
--- a/test/api/services/ShlinkApiClient.test.ts
+++ b/test/api/services/ShlinkApiClient.test.ts
@@ -1,8 +1,8 @@
import { fromPartial } from '@total-typescript/shoehorn';
+import type { ShlinkDomain, ShlinkVisits, ShlinkVisitsOverview } from '../../../shlink-web-component/src/api-contract';
+import { ErrorTypeV2, ErrorTypeV3 } from '../../../shlink-web-component/src/api-contract';
import type { ShortUrl, ShortUrlsOrder } from '../../../shlink-web-component/src/short-urls/data';
import { ShlinkApiClient } from '../../../src/api/services/ShlinkApiClient';
-import type { ShlinkDomain, ShlinkVisits, ShlinkVisitsOverview } from '../../../src/api/types';
-import { ErrorTypeV2, ErrorTypeV3 } from '../../../src/api/types/errors';
import type { HttpClient } from '../../../src/common/services/HttpClient';
import type { OptionalString } from '../../../src/utils/utils';
diff --git a/test/app/App.test.tsx b/test/app/App.test.tsx
index 70ad630a..34963f1d 100644
--- a/test/app/App.test.tsx
+++ b/test/app/App.test.tsx
@@ -8,7 +8,7 @@ describe('', () => {
const App = createApp(
() => <>MainHeader>,
() => <>Home>,
- () => <>MenuLayout>,
+ () => <>ShlinkWebComponentContainer>,
() => <>CreateServer>,
() => <>EditServer>,
() => <>SettingsComp>,
@@ -47,8 +47,8 @@ describe('', () => {
['/server/create', 'CreateServer'],
['/server/abc123/edit', 'EditServer'],
['/server/def456/edit', 'EditServer'],
- ['/server/abc123/foo', 'MenuLayout'],
- ['/server/def456/bar', 'MenuLayout'],
+ ['/server/abc123/foo', 'ShlinkWebComponentContainer'],
+ ['/server/def456/bar', 'ShlinkWebComponentContainer'],
['/other', 'Oops! We could not find requested route.'],
])('renders expected route', async (activeRoute, expectedComponent) => {
setUp(activeRoute);
diff --git a/test/common/MenuLayout.test.tsx b/test/common/MenuLayout.test.tsx
deleted file mode 100644
index 08c940e6..00000000
--- a/test/common/MenuLayout.test.tsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import { render, screen } from '@testing-library/react';
-import { fromPartial } from '@total-typescript/shoehorn';
-import { createMemoryHistory } from 'history';
-import { Router, useParams } from 'react-router-dom';
-import { MenuLayout as createMenuLayout } from '../../src/common/MenuLayout';
-import type { NonReachableServer, NotFoundServer, SelectedServer } from '../../src/servers/data';
-import type { SemVer } from '../../src/utils/helpers/version';
-
-vi.mock('react-router-dom', async () => ({
- ...(await vi.importActual('react-router-dom')),
- useParams: vi.fn(),
-}));
-
-describe('', () => {
- const MenuLayout = createMenuLayout(
- () => <>TagsList>,
- () => <>ShortUrlsList>,
- () => <>CreateShortUrl>,
- () => <>ShortUrlVisits>,
- () => <>TagVisits>,
- () => <>DomainVisits>,
- () => <>OrphanVisits>,
- () => <>NonOrphanVisits>,
- () => <>ServerError>,
- () => <>OverviewRoute>,
- () => <>EditShortUrl>,
- () => <>ManageDomains>,
- );
- const setUp = (selectedServer: SelectedServer, currentPath = '/') => {
- const history = createMemoryHistory();
- history.push(currentPath);
-
- return render(
-
-
- ,
- );
- };
-
- beforeEach(() => {
- (useParams as any).mockReturnValue({ serverId: 'abc123' });
- });
-
- it('shows loading indicator while loading server', () => {
- setUp(null);
-
- expect(screen.getByText('Loading...')).toBeInTheDocument();
- expect(screen.queryByText('ServerError')).not.toBeInTheDocument();
- });
-
- it.each([
- [fromPartial({ serverNotFound: true })],
- [fromPartial({ serverNotReachable: true })],
- ])('shows error for non reachable servers', (selectedServer) => {
- setUp(selectedServer);
-
- expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
- expect(screen.getByText('ServerError')).toBeInTheDocument();
- });
-
- it.each([
- ['3.0.0' as SemVer, '/overview', 'OverviewRoute'],
- ['3.0.0' as SemVer, '/list-short-urls/1', 'ShortUrlsList'],
- ['3.0.0' as SemVer, '/create-short-url', 'CreateShortUrl'],
- ['3.0.0' as SemVer, '/short-code/abc123/visits/foo', 'ShortUrlVisits'],
- ['3.0.0' as SemVer, '/short-code/abc123/edit', 'EditShortUrl'],
- ['3.0.0' as SemVer, '/tag/foo/visits/foo', 'TagVisits'],
- ['3.0.0' as SemVer, '/orphan-visits/foo', 'OrphanVisits'],
- ['3.0.0' as SemVer, '/manage-tags', 'TagsList'],
- ['3.0.0' as SemVer, '/not-found', 'Oops! We could not find requested route.'],
- ['3.0.0' as SemVer, '/domain/domain.com/visits/foo', 'Oops! We could not find requested route.'],
- ['3.1.0' as SemVer, '/domain/domain.com/visits/foo', 'DomainVisits'],
- ['2.10.0' as SemVer, '/non-orphan-visits/foo', 'Oops! We could not find requested route.'],
- ['3.0.0' as SemVer, '/non-orphan-visits/foo', 'NonOrphanVisits'],
- ['2.8.0' as SemVer, '/manage-domains', 'ManageDomains'],
- ])(
- 'renders expected component based on location and server version',
- (version, currentPath, expectedContent) => {
- setUp(fromPartial({ version }), currentPath);
- expect(screen.getByText(expectedContent)).toBeInTheDocument();
- },
- );
-});
diff --git a/test/common/ShlinkWebComponentContainer.test.tsx b/test/common/ShlinkWebComponentContainer.test.tsx
new file mode 100644
index 00000000..feae7b9c
--- /dev/null
+++ b/test/common/ShlinkWebComponentContainer.test.tsx
@@ -0,0 +1,82 @@
+import { render, screen } from '@testing-library/react';
+import { fromPartial } from '@total-typescript/shoehorn';
+import { useParams } from 'react-router-dom';
+import { ShlinkWebComponentContainer as createContainer } from '../../src/common/ShlinkWebComponentContainer';
+import type { NonReachableServer, NotFoundServer, SelectedServer } from '../../src/servers/data';
+
+vi.mock('react-router-dom', async () => ({
+ ...(await vi.importActual('react-router-dom')),
+ useParams: vi.fn(),
+}));
+
+describe('', () => {
+ const ShlinkWebComponentContainer = createContainer(
+ vi.fn().mockReturnValue(fromPartial({})),
+ () => <>ShlinkWebComponent>,
+ () => <>ServerError>,
+ );
+ const setUp = (selectedServer: SelectedServer) => render(
+ ,
+ );
+
+ beforeEach(() => {
+ (useParams as any).mockReturnValue({ serverId: 'abc123' });
+ });
+
+ it('shows loading indicator while loading server', () => {
+ setUp(null);
+
+ expect(screen.getByText('Loading...')).toBeInTheDocument();
+ expect(screen.queryByText('ServerError')).not.toBeInTheDocument();
+ expect(screen.queryByText('ShlinkWebComponent')).not.toBeInTheDocument();
+ });
+
+ it.each([
+ [fromPartial({ serverNotFound: true })],
+ [fromPartial({ serverNotReachable: true })],
+ ])('shows error for non reachable servers', (selectedServer) => {
+ setUp(selectedServer);
+
+ expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
+ expect(screen.getByText('ServerError')).toBeInTheDocument();
+ expect(screen.queryByText('ShlinkWebComponent')).not.toBeInTheDocument();
+ });
+
+ it('renders ShlinkWebComponent for reachable servers', () => {
+ setUp(fromPartial({ version: '3.0.0' }));
+
+ expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
+ expect(screen.queryByText('ServerError')).not.toBeInTheDocument();
+ expect(screen.getByText('ShlinkWebComponent')).toBeInTheDocument();
+ });
+
+ // FIXME Move this case to ShlinkWebComponent test
+ // it.each([
+ // ['3.0.0' as SemVer, '/overview', 'OverviewRoute'],
+ // ['3.0.0' as SemVer, '/list-short-urls/1', 'ShortUrlsList'],
+ // ['3.0.0' as SemVer, '/create-short-url', 'CreateShortUrl'],
+ // ['3.0.0' as SemVer, '/short-code/abc123/visits/foo', 'ShortUrlVisits'],
+ // ['3.0.0' as SemVer, '/short-code/abc123/edit', 'EditShortUrl'],
+ // ['3.0.0' as SemVer, '/tag/foo/visits/foo', 'TagVisits'],
+ // ['3.0.0' as SemVer, '/orphan-visits/foo', 'OrphanVisits'],
+ // ['3.0.0' as SemVer, '/manage-tags', 'TagsList'],
+ // ['3.0.0' as SemVer, '/not-found', 'Oops! We could not find requested route.'],
+ // ['3.0.0' as SemVer, '/domain/domain.com/visits/foo', 'Oops! We could not find requested route.'],
+ // ['3.1.0' as SemVer, '/domain/domain.com/visits/foo', 'DomainVisits'],
+ // ['2.10.0' as SemVer, '/non-orphan-visits/foo', 'Oops! We could not find requested route.'],
+ // ['3.0.0' as SemVer, '/non-orphan-visits/foo', 'NonOrphanVisits'],
+ // ['2.8.0' as SemVer, '/manage-domains', 'ManageDomains'],
+ // ])(
+ // 'renders expected component based on location and server version',
+ // (version, currentPath, expectedContent) => {
+ // setUp(fromPartial({ version }), currentPath);
+ // expect(screen.getByText(expectedContent)).toBeInTheDocument();
+ // },
+ // );
+});
diff --git a/test/servers/ManageServers.test.tsx b/test/servers/ManageServers.test.tsx
index ce01fc80..3a29c79d 100644
--- a/test/servers/ManageServers.test.tsx
+++ b/test/servers/ManageServers.test.tsx
@@ -58,11 +58,11 @@ describe('', () => {
expect(screen.getAllByRole('columnheader')).toHaveLength(expectedCols);
if (server.autoConnect) {
- expect(screen.getByText(/\[YES\]/)).toBeInTheDocument();
- expect(screen.queryByText(/\[NO\]/)).not.toBeInTheDocument();
+ expect(screen.getByText(/\[YES]/)).toBeInTheDocument();
+ expect(screen.queryByText(/\[NO]/)).not.toBeInTheDocument();
} else {
- expect(screen.queryByText(/\[YES\]/)).not.toBeInTheDocument();
- expect(screen.getByText(/\[NO\]/)).toBeInTheDocument();
+ expect(screen.queryByText(/\[YES]/)).not.toBeInTheDocument();
+ expect(screen.getByText(/\[NO]/)).toBeInTheDocument();
}
});
diff --git a/test/settings/RealTimeUpdatesSettings.test.tsx b/test/settings/RealTimeUpdatesSettings.test.tsx
index 86815061..a30bff4b 100644
--- a/test/settings/RealTimeUpdatesSettings.test.tsx
+++ b/test/settings/RealTimeUpdatesSettings.test.tsx
@@ -1,9 +1,7 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
+import type { RealTimeUpdatesSettings as RealTimeUpdatesSettingsOptions } from '../../shlink-web-component/src';
import { RealTimeUpdatesSettings } from '../../src/settings/RealTimeUpdatesSettings';
-import type {
- RealTimeUpdatesSettings as RealTimeUpdatesSettingsOptions,
-} from '../../src/settings/reducers/settings';
import { renderWithEvents } from '../__helpers__/setUpTest';
describe('', () => {
diff --git a/test/settings/ShortUrlCreationSettings.test.tsx b/test/settings/ShortUrlCreationSettings.test.tsx
index da21d4d3..72d3c511 100644
--- a/test/settings/ShortUrlCreationSettings.test.tsx
+++ b/test/settings/ShortUrlCreationSettings.test.tsx
@@ -1,6 +1,6 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
-import type { ShortUrlCreationSettings as ShortUrlsSettings } from '../../src/settings/reducers/settings';
+import type { ShortUrlCreationSettings as ShortUrlsSettings } from '../../shlink-web-component/src';
import { ShortUrlCreationSettings } from '../../src/settings/ShortUrlCreationSettings';
import { renderWithEvents } from '../__helpers__/setUpTest';
diff --git a/test/settings/ShortUrlsListSettings.test.tsx b/test/settings/ShortUrlsListSettings.test.tsx
index e48bb200..fc0d0ab9 100644
--- a/test/settings/ShortUrlsListSettings.test.tsx
+++ b/test/settings/ShortUrlsListSettings.test.tsx
@@ -1,7 +1,7 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
+import type { ShortUrlsListSettings as ShortUrlsSettings } from '../../shlink-web-component/src';
import type { ShortUrlsOrder } from '../../shlink-web-component/src/short-urls/data';
-import type { ShortUrlsListSettings as ShortUrlsSettings } from '../../src/settings/reducers/settings';
import { ShortUrlsListSettings } from '../../src/settings/ShortUrlsListSettings';
import { renderWithEvents } from '../__helpers__/setUpTest';
diff --git a/test/settings/TagsSettings.test.tsx b/test/settings/TagsSettings.test.tsx
index de6935b8..69bc28b3 100644
--- a/test/settings/TagsSettings.test.tsx
+++ b/test/settings/TagsSettings.test.tsx
@@ -1,7 +1,7 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
+import type { TagsSettings as TagsSettingsOptions } from '../../shlink-web-component/src';
import type { TagsOrder } from '../../shlink-web-component/src/tags/data/TagsListChildrenProps';
-import type { TagsSettings as TagsSettingsOptions } from '../../src/settings/reducers/settings';
import { TagsSettings } from '../../src/settings/TagsSettings';
import { renderWithEvents } from '../__helpers__/setUpTest';
diff --git a/test/settings/UserInterfaceSettings.test.tsx b/test/settings/UserInterfaceSettings.test.tsx
index b8c8c618..99fb2388 100644
--- a/test/settings/UserInterfaceSettings.test.tsx
+++ b/test/settings/UserInterfaceSettings.test.tsx
@@ -1,6 +1,6 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
-import type { UiSettings } from '../../src/settings/reducers/settings';
+import type { UiSettings } from '../../shlink-web-component/src';
import { UserInterfaceSettings } from '../../src/settings/UserInterfaceSettings';
import type { Theme } from '../../src/utils/theme';
import { renderWithEvents } from '../__helpers__/setUpTest';
diff --git a/test/settings/VisitsSettings.test.tsx b/test/settings/VisitsSettings.test.tsx
index 960e60fe..f1799d1c 100644
--- a/test/settings/VisitsSettings.test.tsx
+++ b/test/settings/VisitsSettings.test.tsx
@@ -1,6 +1,6 @@
import { screen } from '@testing-library/react';
import { fromPartial } from '@total-typescript/shoehorn';
-import type { Settings } from '../../src/settings/reducers/settings';
+import type { Settings } from '../../shlink-web-component/src';
import { VisitsSettings } from '../../src/settings/VisitsSettings';
import { renderWithEvents } from '../__helpers__/setUpTest';
diff --git a/test/utils/helpers/version.test.ts b/test/utils/helpers/version.test.ts
index 44888723..382151b6 100644
--- a/test/utils/helpers/version.test.ts
+++ b/test/utils/helpers/version.test.ts
@@ -1,7 +1,6 @@
import { fromPartial } from '@total-typescript/shoehorn';
-import type { SemVer, Versions } from '../../../src/utils/helpers/version';
+import type { Empty, SemVer, Versions } from '../../../src/utils/helpers/version';
import { versionMatch } from '../../../src/utils/helpers/version';
-import type { Empty } from '../../../src/utils/utils';
describe('version', () => {
describe('versionMatch', () => {