diff --git a/packages/webview/src/component/dashboard/KubernetesProviderCard.spec.ts b/packages/webview/src/component/dashboard/KubernetesProviderCard.spec.ts new file mode 100644 index 00000000..a49f68ba --- /dev/null +++ b/packages/webview/src/component/dashboard/KubernetesProviderCard.spec.ts @@ -0,0 +1,69 @@ +/********************************************************************** + * Copyright (C) 2025 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import '@testing-library/jest-dom/vitest'; + +import { render, screen } from '@testing-library/svelte'; +import { beforeEach, expect, test, vi } from 'vitest'; +import KubernetesProviderCard from '/@/component/dashboard/KubernetesProviderCard.svelte'; +import { RemoteMocks } from '/@/tests/remote-mocks'; +import { API_NAVIGATION } from '@kubernetes-dashboard/channels'; +import type { NavigationApi } from '@kubernetes-dashboard/channels'; +import userEvent from '@testing-library/user-event'; + +const remoteMocks = new RemoteMocks(); + +beforeEach(() => { + vi.resetAllMocks(); + remoteMocks.reset(); + + remoteMocks.mock(API_NAVIGATION, { + navigateToProviderNewConnection: vi.fn(), + } as unknown as NavigationApi); +}); + +test('should render with all values passed', async () => { + render(KubernetesProviderCard, { + provider: { + id: 'k8s-provider', + creationDisplayName: 'Kubernetes Provider', + creationButtonTitle: 'Create Kubernetes Provider', + emptyConnectionMarkdownDescription: 'Create a new Kubernetes Provider', + }, + }); + screen.getByText('Kubernetes Provider'); + screen.getByText('Create Kubernetes Provider'); + const btn = screen.getByRole('button', { name: 'Create Kubernetes Provider' }); + expect(btn).toBeEnabled(); + await userEvent.click(btn); + expect(remoteMocks.get(API_NAVIGATION).navigateToProviderNewConnection).toHaveBeenCalledWith('k8s-provider'); +}); + +test('should render with minimal values passed', async () => { + render(KubernetesProviderCard, { + provider: { + id: 'k8s-provider', + }, + }); + screen.getByText('Create'); + screen.getByText('Create new'); + const btn = screen.getByRole('button', { name: 'Create new' }); + expect(btn).toBeEnabled(); + await userEvent.click(btn); + expect(remoteMocks.get(API_NAVIGATION).navigateToProviderNewConnection).toHaveBeenCalledWith('k8s-provider'); +}); diff --git a/packages/webview/src/component/dashboard/KubernetesProviderCard.svelte b/packages/webview/src/component/dashboard/KubernetesProviderCard.svelte new file mode 100644 index 00000000..e77b7db2 --- /dev/null +++ b/packages/webview/src/component/dashboard/KubernetesProviderCard.svelte @@ -0,0 +1,47 @@ + + +
+
+ +
+

+ {provider.creationDisplayName ?? 'Create'} +

+ +

+ +

+ +
+ +
+
diff --git a/packages/webview/src/component/dashboard/NoContextPage.spec.ts b/packages/webview/src/component/dashboard/NoContextPage.spec.ts new file mode 100644 index 00000000..f6b14618 --- /dev/null +++ b/packages/webview/src/component/dashboard/NoContextPage.spec.ts @@ -0,0 +1,118 @@ +/********************************************************************** + * Copyright (C) 2025 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ***********************************************************************/ + +import '@testing-library/jest-dom/vitest'; + +import { render, screen } from '@testing-library/svelte'; +import { beforeEach, expect, test, vi } from 'vitest'; +import NoContextPage from './NoContextPage.svelte'; +import { StatesMocks } from '/@/tests/state-mocks'; +import { FakeStateObject } from '/@/state/util/fake-state-object.svelte'; +import type { KubernetesProvidersInfo } from '@kubernetes-dashboard/channels'; +import KubeIcon from '/@/component/icons/KubeIcon.svelte'; +import KubernetesProviderCard from '/@/component/dashboard/KubernetesProviderCard.svelte'; +import type { Unsubscriber } from 'svelte/store'; + +vi.mock(import('./KubernetesProviderCard.svelte')); +vi.mock(import('/@/component/icons/KubeIcon.svelte')); + +const statesMocks = new StatesMocks(); +let kubernetesProvidersMock: FakeStateObject; + +beforeEach(() => { + vi.resetAllMocks(); + statesMocks.reset(); + + kubernetesProvidersMock = new FakeStateObject(); + statesMocks.mock('stateKubernetesProvidersInfoUI', kubernetesProvidersMock); +}); + +test('should render the Kubernetes icon', () => { + render(NoContextPage); + expect(KubeIcon).toHaveBeenCalledWith(expect.anything(), { size: '80' }); +}); + +test('should render the main heading', () => { + render(NoContextPage); + + const heading = screen.getByRole('heading', { level: 1 }); + expect(heading).toHaveTextContent('No Kubernetes cluster'); +}); + +test('should render the description text', () => { + render(NoContextPage); + + const description = screen.getByText(/A Kubernetes cluster is a group of nodes/); + expect(description).toBeInTheDocument(); + expect(description).toHaveClass('text-[var(--pd-details-empty-sub-header)]', 'text-balance'); +}); + +test('should render providers when data is available', () => { + const mockProviders: KubernetesProvidersInfo = { + providers: [ + { + id: 'provider-1', + creationDisplayName: 'Provider 1', + creationButtonTitle: 'Create Provider 1', + emptyConnectionMarkdownDescription: 'Description 1', + }, + { + id: 'provider-2', + creationDisplayName: 'Provider 2', + creationButtonTitle: 'Create Provider 2', + emptyConnectionMarkdownDescription: 'Description 2', + }, + ], + }; + + kubernetesProvidersMock.setData(mockProviders); + render(NoContextPage); + + expect(KubernetesProviderCard).toHaveBeenCalledWith(expect.anything(), { provider: mockProviders.providers[0] }); + expect(KubernetesProviderCard).toHaveBeenCalledWith(expect.anything(), { provider: mockProviders.providers[1] }); +}); + +test('should handle providers with minimal data', () => { + const mockProviders = { + providers: [ + { + id: 'minimal-provider', + }, + ], + }; + + kubernetesProvidersMock.setData(mockProviders); + render(NoContextPage); + + expect(KubernetesProviderCard).toHaveBeenCalledWith(expect.anything(), { provider: mockProviders.providers[0] }); +}); + +test('should call subscribe on mount', () => { + render(NoContextPage); + + expect(kubernetesProvidersMock.subscribe).toHaveBeenCalledTimes(1); +}); + +test('should call unsubscribe on unmount', () => { + const unsubscribeMock: Unsubscriber = vi.fn(); + vi.mocked(kubernetesProvidersMock.subscribe).mockReturnValue(unsubscribeMock); + const component = render(NoContextPage); + + component.unmount(); + expect(unsubscribeMock).toHaveBeenCalledTimes(1); +}); diff --git a/packages/webview/src/component/dashboard/NoContextPage.svelte b/packages/webview/src/component/dashboard/NoContextPage.svelte index 15984556..cfc5c1d4 100644 --- a/packages/webview/src/component/dashboard/NoContextPage.svelte +++ b/packages/webview/src/component/dashboard/NoContextPage.svelte @@ -1,16 +1,38 @@
-
+

No Kubernetes cluster

-
+
A Kubernetes cluster is a group of nodes (virtual or physical) that run Kubernetes, a system for automating the deployment and management of containerized applications.
+
+ {#each kubernetesProviders.data?.providers as provider (provider.id)} + + {/each} +