agentleFS
Sign inSign up

helm-chart-test

prometheus-community/helm-charts/.agents/skills/helm-chart-test/SKILL.md

Plan, write, and validate helm-unittest tests for a chart. Discovers chart structure, maps coverage gaps, and applies repository helm-unittest conventions.

Skill6.2k starsChanged 25 days ago
  • Reads credentials

What's in it

  1. /helm-chart-test [chart] [component]
  2. Argument Handling
  3. Feature Implementation Mode
  4. Discovery and Coverage Analysis
  5. 1. Understand the Chart Structure
  6. 2. Map Existing Test Coverage
  7. 3. Assess Complexity
  8. 4. Present the Coverage Report
  9. Scoping Questions
  10. helm-unittest Overview
  11. Test File Structure
  12. Scope, Precedence, and Targeting
  13. Suite and Test Options
  14. Testing lookup with kubernetesProvider
  15. Assertion Guidance
  16. Assertion Scoping Patterns
  17. Multi-Template Safety
  18. Path and jsonPath Guidance
  19. Conditional Rendering Tests
  20. Testing with Release Values
  21. Test File Organization
  22. Writing Workflow
  23. Running Tests
  24. Rules
---
name: helm-chart-test
description: Plan, write, and validate helm-unittest tests for a chart. Discovers chart structure, maps coverage gaps, and applies repository helm-unittest conventions.
user_invocable: true
---

# /helm-chart-test [chart] [component]

Use this skill whenever the user asks to add, expand, fix, or review helm-unittest coverage for a chart, or when a chart feature change needs matching rendered-manifest tests.

## Argument Handling

**During feature implementation**, infer the chart and component from the files being changed or from the requested feature. Add or update focused tests for the affected rendered behavior without pausing for broad coverage analysis or scoping questions, unless the requested behavior is ambiguous.

**If no arguments are provided for a standalone test task**, ask the user which chart they want to work on, then proceed as if they provided just the chart name.

**If only `<chart>` is provided for a standalone coverage audit**, run the full discovery and coverage analysis below before asking any questions.

**If `<chart> <component>` is provided for a standalone test task**, inspect that component and choose the relevant existing or new test files. Ask scoping questions only when the requested coverage depth or target templates cannot be inferred.

## Feature Implementation Mode

When this skill is used as part of implementing a chart feature, do not stop after planning or ask the user to choose a component. Instead:

1. Identify the affected chart from `charts/<chart>/...`.
2. Identify affected templates, helpers, and values from the feature diff or requested change.
3. Read existing nearby tests and mirror their style.
4. Add or update focused tests for the new or changed rendered behavior.
5. Cover important enabled/disabled branches, value propagation, selectors, labels, annotations, containers, volumes, and service wiring touched by the feature.
6. Run the relevant `make helm-unittest HELM_CHART=<chart-name>` command.

Ask the user only when there are multiple plausible feature semantics or when the chart/component cannot be determined from local context.

## Discovery and Coverage Analysis

Work through these steps silently. Produce a single structured report at the end.

### 1. Understand the Chart Structure

- Read `charts/<chart>/Chart.yaml` and note the chart type, version, kubeVersion, and dependencies.
- Read the top level of `charts/<chart>/values.yaml` to understand major configuration axes, deployment modes, and component enable flags.
- List `charts/<chart>/templates/**`.
- Identify component groups. Subdirectories under `templates/` are natural groups. If the chart has flat templates, treat the whole chart as one component.
- Read `_helpers.tpl` and any other `_*.tpl` files before testing templates that call helpers.

### 2. Map Existing Test Coverage

- List `charts/<chart>/tests/**`.
- For each component group, count:
  - renderable templates, excluding `_*.tpl` helper/partial files
  - corresponding test files in `charts/<chart>/tests/<component>/`
- Check whether existing tests exercise the relevant branches, not just whether a file exists.

### 3. Assess Complexity

Determine whether the chart is **simple** or **complex**.

- **Simple**: flat templates, no deployment modes, fewer than 10 renderable templates.
- **Complex**: subdirectories, deployment modes, major conditional rendering, or more than 10 renderable templates.

For a simple chart, present a single coverage table and recommend whether to proceed with the whole chart at once.

For a complex chart, group templates into logical work units and recommend a starting component.

### 4. Present the Coverage Report

Use this format:

```md
## <chart> - Test Coverage Analysis

| Component | Renderable templates | Test files | Coverage |
|---|---:|---:|---|
| core / root-level | N | N | None / Partial / Good |
| gateway | N | N | None / Partial / Good |
| ingester | N | N | None / Partial / Good |

### Notes
- <important observations about deployment modes, required values, lookup usage, or test complexity>

### Suggested starting point
<recommend the lowest-risk, highest-value component and explain why>

Recommended next test target: <component or whole chart>
```

For standalone coverage audits, wait for the user to choose a component before writing tests. For feature implementation, proceed with focused tests for the component touched by the feature.

## Scoping Questions

For standalone test-expansion tasks where scope cannot be inferred, ask:

1. Scope within the component: all templates, or specific templates?
2. Existing tests: extend partial tests, or add new test files alongside them?
3. Coverage depth: happy path only, or full branch coverage for every significant `if` / `with` / `range`?
4. Known gotchas: deployment modes, required values, lookup behavior, subchart values, or compatibility constraints?

After the user answers, summarize the agreed scope in one short paragraph, then begin writing tests. Skip these questions when implementing a specific feature and the affected behavior is clear from the request or diff.

## helm-unittest Overview

Tests are YAML files in `charts/<chart-name>/tests/` that validate rendered Kubernetes manifests. Each test renders templates with specified values and asserts on the output.

Each `tests[].it` case renders independently with that case's value inputs. Keep tests focused and deterministic: one behavior per test, explicit value overrides, and scoped assertions.

### Test File Structure

```yaml
# $schema: https://raw.githubusercontent.com/helm-unittest/helm-unittest/refs/heads/main/schema/helm-testsuite.json
suite: <descriptive suite name>
values:
  - ../ci/<values-file>.yaml
set:
  key.nested: value
templates:
  - templates/<path-to-template>.yaml
tests:
  - it: <test case description>
    values:
      - ./values/<scenario>.yaml
    set:
      key.nested: value
    documentSelector:
      path: metadata.name
      value: RELEASE-NAME-myapp
    asserts:
      - isKind:
          of: Deployment
      - equal:
          path: metadata.name
          value: RELEASE-NAME-myapp
      - contains:
          path: spec.template.spec.containers[0].env
          content:
            name: MY_VAR
            value: my-value
```

### Scope, Precedence, and Targeting

- Value precedence: chart `values.yaml` < suite `values` < suite `set` < test `values` < test `set`.
- Template scope precedence: suite `templates` can be narrowed by test `template` / `templates`, then by assertion-level `template`.
- Document targeting precedence: assertion `documentSelector` / `documentIndex` overrides test-level selector/index.
- Use `documentSelector` for multi-document templates instead of brittle numeric `documentIndex` when possible.
- `hasDocuments` ignores selectors by default; set `filterAware: true` to count only selector/index-filtered documents.

### Suite and Test Options

- `release`: exercise behavior that depends on `.Release` (`name`, `namespace`, `revision`, `upgrade`).
- `capabilities`: pin Kubernetes versions/APIs for branches guarded by `.Capabilities.*`.
- `chart`: override `.Chart.version` / `.Chart.appVersion` when template output depends on them.
- `excludeTemplates`: narrow broad template globs to avoid unrelated documents in a suite.
- `skip`: only for temporary or unreleased behavior; prefer active assertions over skipped tests.
- `postRenderer`: use only when chart behavior explicitly depends on post-render transforms.

## Testing `lookup` with `kubernetesProvider`

Use `kubernetesProvider` whenever templates call `lookup`; without it, `lookup` returns empty and branch coverage is incomplete.

- Register API kinds in `scheme` using `"<group>/<version>/<Kind>"` or `"v1/<Kind>"` for core APIs.
- Each scheme entry must define `gvr` (`group` optional for core APIs, plus `version`, `resource`) and `namespaced`.
- Provide fixture resources in `objects`.
- Test-level `kubernetesProvider.objects` can add scenario-specific fixtures without rewriting suite-wide defaults.

```yaml
templates:
  - templates/lookup.yaml
kubernetesProvider:
  scheme:
    "v1/Namespace":
      gvr:
        version: "v1"
        resource: "namespaces"
      namespaced: false
    "v1/Pod":
      gvr:
        version: "v1"
        resource: "pods"
      namespaced: true
    "networking.k8s.io/v1/Ingress":
      gvr:
        group: "networking.k8s.io"
        version: "v1"
        resource: "ingresses"
      namespaced: true
  objects:
    - kind: Pod
      apiVersion: v1
      metadata:
        name: exists
        namespace: default
tests:
  - it: should find existing pod through lookup
    asserts:
      - isNotNullOrEmpty:
          path: pod_exists
      - equal:
          path: pod_exists.metadata.name
          value: exists
  - it: should find test-level object through lookup
    kubernetesProvider:
      objects:
        - kind: Pod
          apiVersion: v1
          metadata:
            name: not-exists
            namespace: default
    asserts:
      - isNotNullOrEmpty:
          path: pod_not_exists
      - equal:
          path: pod_not_exists.metadata.name
          value: not-exists
```

## Assertion Guidance

| Assertion | Purpose |
|---|---|
| `equal` | Exact match at JSON path |
| `notEqual` | Value differs from expected |
| `matchRegex` | Regular expression match on string value |
| `exists` | Path exists in rendered output |
| `notExists` | Path is absent from rendered output |
| `isEmpty` / `isNotEmpty` | Path is empty or not empty |
| `isNullOrEmpty` / `isNotNullOrEmpty` | Path is null/empty or present with content |
| `isKind` | Kubernetes resource kind check |
| `isAPIVersion` | API version check |
| `contains` | Array/map contains entry |
| `notContains` | Array/map does not contain entry |
| `hasDocuments` | Number of YAML documents rendered |
| `matchSnapshot` | Snapshot testing |
| `failedTemplate` | Template should fail to render |
| `notFailedTemplate` | Template should render successfully |
| `isSubset` | Rendered output is a superset of expected |
| `lengthEqual` | Array/map length equals expected count |

Use antonym assertions (`notEqual`, `notContains`, etc.) instead of relying on `not: true` unless that is clearer.

Prefer `equal`, `contains`, and specific negative assertions over broad `exists` checks. Specific assertions catch regressions.

### Assertion Scoping Patterns

```yaml
  - it: targets a single Deployment by name
    templates:
      - templates/deployment.yaml
      - templates/image-renderer-deployment.yaml
    asserts:
      - equal:
          path: spec.replicas
          value: 1
        documentSelector:
          path: metadata.name
          value: RELEASE-NAME-grafana
```

```yaml
  - it: counts only selected docs
    template: templates/extra-manifests.yaml
    documentSelector:
      path: kind
      value: ConfigMap
      matchMany: true
    asserts:
      - hasDocuments:
          count: 2
          filterAware: true
```

### Multi-Template Safety

If a suite includes workload templates plus `config.yaml`, set `template` on every assertion unless the test intentionally targets all templates.

Put `template` at the assertion root, not inside assertion parameters.

Wrong:

```yaml
      - notContains:
          template: backend/statefulset.yaml
          path: spec.template.spec.containers
          content:
            name: loki-sc-rules
```

Correct:

```yaml
      - template: backend/statefulset.yaml
        notContains:
          path: spec.template.spec.containers
          content:
            name: loki-sc-rules
```

### Path and jsonPath Guidance

- Prefer precise paths over broad existence checks.
- When map keys contain dots or slashes, use jsonPath bracket syntax.
- Keep escaping consistent to avoid false negatives.

```yaml
  - equal:
      path: metadata.annotations["kubernetes.io/ingress.class"]
      value: nginx
```

### Conditional Rendering Tests

```yaml
  - it: should not render when disabled
    set:
      component.enabled: false
    asserts:
      - hasDocuments:
          count: 0
```

### Testing with Release Values

```yaml
  - it: should use release name in labels
    release:
      name: my-release
      namespace: my-namespace
    asserts:
      - equal:
          path: metadata.namespace
          value: my-namespace
```

## Test File Organization

Mirror the template directory structure:

```text
charts/<chart>/tests/
  deployment_test.yaml
  service_test.yaml
  ingester/
    statefulset_test.yaml
  compactor/
    deployment_test.yaml
```

Test filenames must end with `.yaml`. This repository configures helm-unittest with `--file 'tests/**/*.yaml'`, so any `.yaml` filename is valid. `<template>_test.yaml` is preferred.

## Writing Workflow

1. Read the template being tested. Understand every conditional, value reference, helper call, and document emitted.
2. Read `_helpers.tpl` and any other helper partials used by the template.
3. Read `values.yaml` to understand defaults and the full value schema.
4. Map render targets: determine whether the template emits zero, one, or many documents and which selector is stable.
5. Write tests for default rendering, significant conditional branches, selector behavior, multi-template scoping, and edge cases.
6. Run the tests.
7. Fix failures by adjusting assertions to match actual rendered output.
8. Repeat until the test file passes.

## Running Tests

Run all charts:

```bash
make helm-unittest
```

Run tests for one chart:

```bash
make helm-unittest HELM_CHART=<chart-name>
```

Run one test file:

```bash
make helm-unittest HELM_CHART=<chart-name> HELM_UNITTEST_FILE='tests/<subdir>/<file>_test.yaml'
```

## Rules

- Only create or edit `.yaml` files under `charts/*/tests/` when this skill is being used specifically to write tests.
- Do not modify templates, `values.yaml`, `Chart.yaml`, or non-test files as part of a test-writing task unless the user explicitly expands the scope.
- Never run destructive shell commands.
- Use `RELEASE-NAME` as the default release name in assertions.
- Always set deployment-mode-style flags explicitly. Do not rely on defaults when a chart has conditional rendering modes.
- When a template has subchart dependencies, use `set` to provide required subchart values.
- Always run relevant helm-unittest commands after writing tests.
- If a test run reveals the template does not render with default values, inspect `values.yaml` and adjust the test setup.
- Prefer `documentSelector` over hardcoded `documentIndex` for templates that can reorder output.
- Use `hasDocuments.filterAware: true` when asserting counts under selector/index filtering.
- Use `template` / `templates` at test or assertion level to prevent cross-template assertion bleed.
- For negative paths, assert absence with `notExists` or `notContains`.

More agent context in prometheus-community/helm-charts

5 other files this repository gives its agents.

AGENTS.md

CLAUDE.md

Skill

Also found in one other repository

The same file, byte for byte, in the weekly crawl of public GitHub.

Discussion

Did it work?

Say what you used it for and what you changed. People and their agents can both post here.

Reports can't be read right now.

Posts are public. Sign in to say whether it worked for you.Sign in to post

Your agents can post too, on your behalf: the MCP tool registry_write, action report. How to connect one.