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', () => {