diff --git a/.github/workflows/build-container.yml b/.github/workflows/build-container.yml index 9aeaa24479a..f9cae8de6a5 100644 --- a/.github/workflows/build-container.yml +++ b/.github/workflows/build-container.yml @@ -302,6 +302,38 @@ jobs: echo "❌ In-cluster API tests failed with exit code $EXIT_CODE" exit $EXIT_CODE fi + - name: Set up Helm + uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 + with: + version: v3.18.4 + - name: Deploy Headlamp via Helm and run plugin manager tests + run: | + kubectl config use-context test + kubectl create namespace headlamp-helm + echo 'image:' > helm-values.yaml + echo ' registry: ghcr.io' >> helm-values.yaml + echo ' repository: headlamp-k8s/headlamp' >> helm-values.yaml + echo ' tag: latest' >> helm-values.yaml + echo ' pullPolicy: Never' >> helm-values.yaml + echo 'config:' >> helm-values.yaml + echo ' baseURL: "/headlamp-helm"' >> helm-values.yaml + echo 'service:' >> helm-values.yaml + echo ' type: NodePort' >> helm-values.yaml + echo 'pluginsManager:' >> helm-values.yaml + echo ' enabled: true' >> helm-values.yaml + echo ' configContent: |' >> helm-values.yaml + echo ' plugins:' >> helm-values.yaml + echo ' - name: flux' >> helm-values.yaml + echo ' source: https://artifacthub.io/packages/headlamp/headlamp-k8s/flux' >> helm-values.yaml + helm install headlamp ./charts/headlamp --namespace headlamp-helm -f helm-values.yaml + echo "Waiting for headlamp helm deployment to be available..." + kubectl wait deployment -n headlamp-helm headlamp --for condition=Available=True --timeout=120s + IP_ADDRESS=$(kubectl get nodes --context test -o=jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}') + SERVICE_PORT=$(kubectl get services headlamp -n headlamp-helm -o=jsonpath='{.spec.ports[0].nodePort}') + export SERVICE_URL="http://${IP_ADDRESS}:${SERVICE_PORT}/headlamp-helm" + echo "Helm Headlamp URL: $SERVICE_URL" + cd e2e-tests + HEADLAMP_TEST_URL=$SERVICE_URL npx playwright test tests/helmPlugins.spec.ts # Clear disk space by removing unnecessary files, apt files and uninstall some playwright dependencies - name: Clear Disk Space if: steps.cache-image-restore2.outputs.cache-hit != 'true' diff --git a/e2e-tests/tests/headlampPage.ts b/e2e-tests/tests/headlampPage.ts index ede03bb44ba..878bc87c9b0 100644 --- a/e2e-tests/tests/headlampPage.ts +++ b/e2e-tests/tests/headlampPage.ts @@ -26,7 +26,7 @@ export class HeadlampPage { } async a11y() { - const axeBuilder = new AxeBuilder({ page: this.page }); + const axeBuilder = new AxeBuilder({ page: this.page }).disableRules(['region']); const accessibilityResults = await axeBuilder.analyze(); expect(accessibilityResults.violations).toStrictEqual([]); } @@ -139,6 +139,10 @@ export class HeadlampPage { } } + async tableContains(text: string | RegExp, options?: { timeout?: number }) { + await expect(this.page.locator('table')).toContainText(text, options); + } + async clickOnPlugin(pluginName: string) { await this.page.click(`a:has-text("${pluginName}")`); await this.page.waitForLoadState('load'); diff --git a/e2e-tests/tests/helmPlugins.spec.ts b/e2e-tests/tests/helmPlugins.spec.ts new file mode 100644 index 00000000000..d614d7037b4 --- /dev/null +++ b/e2e-tests/tests/helmPlugins.spec.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2025 The Kubernetes Authors + * + * 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. + */ + +/// +import { test } from '@playwright/test'; +import { HeadlampPage } from './headlampPage'; + +let headlampPage: HeadlampPage; + +test.beforeEach(async ({ page }) => { + headlampPage = new HeadlampPage(page); + + await headlampPage.navigateToCluster('main', process.env.HEADLAMP_TEST_TOKEN); +}); + +test('plugin manager should have installed plugins via helm', async () => { + // Wait for plugins to be loaded. + // The plugin we are installing is 'Flux' via Helm. + + await headlampPage.navigateTopage('/settings/plugins', /Plugins/); + + // Check if the plugin is in the list. + // It might take some time for the plugin manager to install it. + await headlampPage.tableContains(/flux/i, { timeout: 60000 }); +}); diff --git a/e2e-tests/tests/namespacesPage.ts b/e2e-tests/tests/namespacesPage.ts index fbc868ae04a..d1cd6962fad 100644 --- a/e2e-tests/tests/namespacesPage.ts +++ b/e2e-tests/tests/namespacesPage.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { AxeBuilder } from '@axe-core/playwright'; import { expect, Page } from '@playwright/test'; @@ -20,7 +21,7 @@ export class NamespacesPage { constructor(private page: Page) {} async a11y() { - const axeBuilder = new AxeBuilder({ page: this.page }); + const axeBuilder = new AxeBuilder({ page: this.page }).disableRules(['region']); const accessibilityResults = await axeBuilder.analyze(); expect(accessibilityResults.violations).toStrictEqual([]); } diff --git a/e2e-tests/tests/podsPage.ts b/e2e-tests/tests/podsPage.ts index 03e6f1aa1ec..c4d86486c56 100644 --- a/e2e-tests/tests/podsPage.ts +++ b/e2e-tests/tests/podsPage.ts @@ -21,7 +21,7 @@ export class podsPage { constructor(private page: Page) {} async a11y() { - const axeBuilder = new AxeBuilder({ page: this.page }); + const axeBuilder = new AxeBuilder({ page: this.page }).disableRules(['region']); const accessibilityResults = await axeBuilder.analyze(); expect(accessibilityResults.violations).toStrictEqual([]); }