Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
454 changes: 454 additions & 0 deletions docs/superpowers/plans/2026-07-16-techpreview-e2e-test-filtering.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
# Tech Preview E2E Test Filtering Design

**Date:** 2026-07-16
**Status:** Approved (updated to include per-feature-gate support)

## Goal

Populate `test-prow-e2e-techpreview.sh` and `test-prow-playwright-e2e-techpreview.sh` so that CI
jobs running against `TechPreviewNoUpgrade` clusters execute only the tests that specifically
require tech preview or a specific feature gate to be enabled, and skip everything else.

A test can declare one of two levels of dependency:

- **TechPreview overall** — the entire `TechPreviewNoUpgrade` feature set must be on.
- **Specific feature gate** — a named gate (e.g. `OLMv1`, `NodeSwap`) must be enabled. Tests at
this level run on *any* cluster where the gate is enabled, regardless of whether the gate is in
TechPreview or has graduated to GA.

This lets a test continue to run correctly after its feature gate graduates without changing the
test itself.

## Background

- `SERVER_FLAGS.techPreview` (boolean) — set by the server when the cluster's FeatureGate
`featureSet` is `TechPreviewNoUpgrade`.
- The OpenShift FeatureGate CR (`config.openshift.io/v1`, cluster-scoped) tracks individual gate
states. `.status.featureGates[]` lists enabled/disabled gates per feature set; the current
cluster's active gates are the ones corresponding to `.spec.featureSet`.
- `oc get featuregate cluster -o jsonpath={.spec.featureSet}` returns `TechPreviewNoUpgrade` on
tech-preview clusters, or empty string on standard clusters.
- Playwright already uses `{ tag: […] }` annotations (`@admin`, `@smoke`, etc.) and supports
`--grep` for tag-based filtering.
- Cypress uses a `before()` / `cy.exec` pattern (see
`frontend/packages/dev-console/integration-tests/support/commands/hooks.ts`) to skip entire
suites based on the cluster's feature set.
- `KubernetesClient` (`frontend/e2e/clients/kubernetes-client.ts`) exposes `customObjectsApi` but
only has `getCustomResource` (namespaced); a `getClusterCustomResource` method needs to be added.

## Tag Convention

| Tag | Meaning |
|-----|---------|
| `@tech-preview` | Test requires `SERVER_FLAGS.techPreview === true` (TechPreviewNoUpgrade overall) |
| `@feature-gate` | Test requires a specific named feature gate; fixture determines which and enforces it |

Both tags are included in the techpreview scripts. The `@feature-gate` tag is also included in the
regular scripts so tests naturally start passing there as gates graduate to GA — no script change
needed at graduation time.

Example:

```ts
// Requires TechPreview overall
test.describe('OLMv1 catalog', { tag: ['@admin', '@tech-preview'] }, () => { … });

// Requires a specific feature gate (runs on TP and GA once the gate graduates)
test.describe('NodeSwap scheduling', { tag: ['@admin', '@feature-gate'] }, () => { … });
```

## Playwright Design

### `techPreviewOnly` fixture

Added to the `TestFixtures` type and `base.extend()` chain in `frontend/e2e/fixtures/index.ts`.
Reads `SERVER_FLAGS.techPreview` from the page and skips if the cluster is not on TechPreview.

```ts
type TestFixtures = {
cleanup: CleanupFixture;
techPreviewOnly: void;
requireFeatureGate: (gateName: string) => Promise<void>;
};

// In base.extend():
techPreviewOnly: async ({ page }, use) => {
const isTechPreview = await page.evaluate(() => window.SERVER_FLAGS.techPreview);
test.skip(!isTechPreview, 'This test requires a TechPreviewNoUpgrade cluster');
await use();
},
```
Comment on lines +64 to +80

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

The Playwright documentation describes an older contract.

  • docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md#L64-L80: document FeatureGate-CR lookup through k8sClient, not SERVER_FLAGS.
  • docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md#L89-L100: show valid narrowing for the CR response.
  • docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md#L113-L126: describe the existing helper and its current return contract.
  • docs/superpowers/plans/2026-07-16-techpreview-e2e-test-filtering.md#L28-L55: update the implementation steps to match the actual fixture.
📍 Affects 2 files
  • docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md#L64-L80 (this comment)
  • docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md#L89-L100
  • docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md#L113-L126
  • docs/superpowers/plans/2026-07-16-techpreview-e2e-test-filtering.md#L28-L55
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md`
around lines 64 - 80, The documentation describes an outdated SERVER_FLAGS-based
contract; update
docs/superpowers/specs/2026-07-16-techpreview-e2e-test-filtering-design.md at
lines 64-80 to document FeatureGate-CR lookup through k8sClient, lines 89-100 to
show valid narrowing of the CR response, and lines 113-126 to match the existing
helper and return contract. Update
docs/superpowers/plans/2026-07-16-techpreview-e2e-test-filtering.md at lines
28-55 so its implementation steps match the actual fixture behavior.


### `requireFeatureGate` fixture

Also added to `fixtures/index.ts`. Returns a callable that a test invokes with the gate name it
needs. Queries the FeatureGate cluster CR via `KubernetesClient` and skips if the gate is not in
the enabled list for the cluster's active feature set.

```ts
requireFeatureGate: async ({ k8sClient }, use) => {
await use(async (gateName: string) => {
const fg = await k8sClient.getClusterCustomResource(
'config.openshift.io', 'v1', 'featuregates', 'cluster',
);
const featureSet: string = fg?.spec?.featureSet ?? '';
const section = (fg?.status?.featureGates ?? []).find(
(s: any) => s.featureSet === featureSet,
);
const enabled: string[] = (section?.enabled ?? []).map((g: any) => g.name);
test.skip(!enabled.includes(gateName), `Feature gate '${gateName}' is not enabled on this cluster`);
});
},
```

Usage in a test:

```ts
test('NodeSwap pod scheduling', async ({ page, requireFeatureGate }) => {
await requireFeatureGate('NodeSwap');
// … rest of test
});
```

### `KubernetesClient.getClusterCustomResource`

A new method on `KubernetesClient` using the existing `customObjectsApi` to fetch cluster-scoped
custom resources (FeatureGate, ClusterVersion, etc.):

```ts
async getClusterCustomResource(
group: string,
version: string,
plural: string,
name: string,
): Promise<any> {
return this.coApi.getClusterCustomObject({ group, version, plural, name });
}
```

### `test-prow-playwright-e2e-techpreview.sh`

Mirrors `test-prow-playwright-e2e.sh` (same env setup, same artifact copy trap) but passes a grep
filter so only TechPreview or feature-gate tests run:

```bash
./integration-tests/test-playwright-e2e.sh -- --grep "@tech-preview|@feature-gate" "$@"
```

No new `playwright.config.ts` project needed.

### `test-prow-playwright-e2e.sh` (regular script — minor addition)

The regular script gains a `--grep @feature-gate` path so that feature-gate tests also run there.
On standard clusters, the `requireFeatureGate` fixture skips any test whose gate is not yet
enabled; as gates graduate the tests pass automatically.

```bash
# In the e2e/release branch of the regular script:
./integration-tests/test-playwright-e2e.sh -- --grep @feature-gate "$@"
```

This is added as a new scenario or combined with the existing `e2e` scenario — exact wiring to
be decided at implementation time based on CI job structure.

## Cypress Design

### Inverted guard hook — TechPreview overall

A new shared support helper at `frontend/integration-tests/support/tech-preview-guard.ts`.
Skips the entire Cypress suite if the cluster is *not* on TechPreview:

```ts
before(function () {
cy.exec('oc get featuregate cluster -o jsonpath={.spec.featureSet}', {
failOnNonZeroExit: false,
}).then((result) => {
if (result.stdout.trim() !== 'TechPreviewNoUpgrade') {
this.skip();
}
});
});
```

### Inverted guard hook — specific feature gate

An additional helper (same file or a companion `feature-gate-guard.ts`) that accepts a gate name
and skips the suite unless that gate appears in the enabled list:

```ts
export function requireFeatureGate(gateName: string): void {
before(function () {
cy.exec(
`oc get featuregate cluster -o jsonpath='{.status.featureGates[*].enabled[*].name}'`,
{ failOnNonZeroExit: false },
).then((result) => {
const enabled = result.stdout.split(/\s+/).filter(Boolean);
if (!enabled.includes(gateName)) {
this.skip();
}
});
});
}
```

Cypress packages call this in their support entry point alongside the TechPreview guard.

### `test-prow-e2e-techpreview.sh`

Mirrors `test-prow-e2e.sh` (same env setup, same `create-user.sh` and CSP check) but runs only
the Cypress packages that have TechPreview or feature-gate suites:

```bash
./integration-tests/test-cypress.sh -p olm -h true
```

Additional packages are added here as tech-preview / feature-gate Cypress tests are written.

## File Inventory

| File | Action |
|------|--------|
| `test-prow-playwright-e2e-techpreview.sh` | Populate (mirrors playwright script + `--grep "@tech-preview\|@feature-gate"`) |
| `test-prow-e2e-techpreview.sh` | Populate (mirrors cypress script + TP/feature-gate packages only) |
| `frontend/e2e/fixtures/index.ts` | Add `techPreviewOnly` and `requireFeatureGate` fixtures |
| `frontend/e2e/clients/kubernetes-client.ts` | Add `getClusterCustomResource` method |
| `frontend/integration-tests/support/tech-preview-guard.ts` | Create — TechPreview Cypress guard + `requireFeatureGate` helper |

## How Tests Participate

### Playwright — TechPreview overall

1. Add `@tech-preview` to the `test.describe` or `test()` tags.
2. Add `techPreviewOnly` to the fixture destructuring list.
3. Remove any manual `test.skip(isTechPreview, …)` guard — the fixture handles it.

### Playwright — specific feature gate

1. Add `@feature-gate` to the tags.
2. Call `await requireFeatureGate('GateName')` as the first line of the test body.

### Cypress — TechPreview overall

1. Import `tech-preview-guard` in the package's support entry point.
2. Add the package to `test-prow-e2e-techpreview.sh`.

### Cypress — specific feature gate

1. Call `requireFeatureGate('GateName')` in the package's support entry point (or individual spec
`before()` if only some tests in the package need it).
2. Add the package to `test-prow-e2e-techpreview.sh`.

## Lifecycle: Feature Gate Graduation

When a gate graduates from TechPreview to GA:

- **Playwright**: no test change needed. The `requireFeatureGate` fixture will find the gate in the
enabled list on GA clusters, and the test already runs via `--grep @feature-gate` in the regular
script.
- **Cypress**: no test change needed. The `requireFeatureGate` guard passes on GA clusters once the
gate is in the enabled list.
- **What does change**: the gate may move from `.status.featureGates[featureSet=TechPreviewNoUpgrade].enabled`
to being enabled by default (not listed as disabled in any feature set). The fixture and guard
both check the enabled list, so this is transparent.
1 change: 1 addition & 0 deletions frontend/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ dynamic-demo-plugin
tsconfig.json
e2e/tsconfig.json
e2e/package.json
integration-tests/tsconfig.json
48 changes: 48 additions & 0 deletions frontend/e2e/fixtures/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export interface SharedTestConfig {

type TestFixtures = {
cleanup: CleanupFixture;
techPreviewOnly: void;
requireFeatureGate: (gateName: string) => Promise<void>;
};

type WorkerFixtures = {
Expand Down Expand Up @@ -58,6 +60,52 @@ export const test = base.extend<TestFixtures, WorkerFixtures>({
{ scope: 'worker' },
],

techPreviewOnly: async ({ k8sClient }, use) => {
let isTechPreview = false;
try {
const fg = await k8sClient.getClusterCustomResource(
'config.openshift.io',
'v1',
'featuregates',
'cluster',
);
isTechPreview = (fg as any)?.spec?.featureSet === 'TechPreviewNoUpgrade';
} catch {
// If the CR can't be read, don't skip — surface the infrastructure error
throw new Error(
`techPreviewOnly: could not read FeatureGate CR 'cluster': check cluster connectivity`,
);
}
test.skip(!isTechPreview, 'This test requires a TechPreviewNoUpgrade cluster');
Comment on lines +63 to +79

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
git ls-files frontend/e2e/fixtures/index.ts
wc -l frontend/e2e/fixtures/index.ts
cat -n frontend/e2e/fixtures/index.ts | sed -n '1,180p'

Repository: openshift/console

Length of output: 4895


🏁 Script executed:

#!/bin/bash
set -euo pipefail
wc -l frontend/e2e/fixtures/index.ts
sed -n '1,180p' frontend/e2e/fixtures/index.ts | nl -ba

Repository: openshift/console

Length of output: 230


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the Kubernetes client method and nearby usages of feature gate handling.
ast-grep outline frontend/e2e/clients/kubernetes-client.ts --view expanded || true
printf '\n---\n'
rg -n "getClusterCustomResource|featureGates|featureSet|TechPreviewNoUpgrade" frontend/e2e -S
printf '\n---\n'
cat -n frontend/e2e/clients/kubernetes-client.ts | sed -n '1,260p'

Repository: openshift/console

Length of output: 14376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline frontend/e2e/clients/kubernetes-client.ts --view expanded || true
printf '\n---\n'
rg -n "getClusterCustomResource|featureGates|featureSet|TechPreviewNoUpgrade" frontend/e2e -S
printf '\n---\n'
sed -n '1,260p' frontend/e2e/clients/kubernetes-client.ts | cat -n

Repository: openshift/console

Length of output: 14376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "interface FeatureGate|type FeatureGate|featureSet:|featureGates:" frontend -S
printf '\n---\n'
rg -n "FeatureGate" frontend -g '!**/node_modules/**' -S

Repository: openshift/console

Length of output: 1250


🏁 Script executed:

#!/bin/bash
set -euo pipefail

wc -l frontend/integration-tests/support/tech-preview-guard.ts
sed -n '1,220p' frontend/integration-tests/support/tech-preview-guard.ts | cat -n

Repository: openshift/console

Length of output: 1629


Guard against malformed FeatureGate payloads before skipping tests.

  • frontend/e2e/fixtures/index.ts#L63-L79: fail when spec.featureSet is missing or not a string; otherwise a bad CR looks like a non-TechPreview cluster and silently skips the suite.
  • frontend/e2e/fixtures/index.ts#L83-L105: fail when the active status.featureGates section or enabled entries are missing or malformed; otherwise a bad CR looks like the gate is disabled.
📍 Affects 1 file
  • frontend/e2e/fixtures/index.ts#L63-L79 (this comment)
  • frontend/e2e/fixtures/index.ts#L83-L105
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/e2e/fixtures/index.ts` around lines 63 - 79, Validate the
FeatureGate payload in the techPreviewOnly fixture before calling test.skip:
require spec.featureSet to be a string and fail with an infrastructure/data
error when missing or malformed. Also update the active status.featureGates
handling in the same fixture to require the section and enabled entries to be
present and correctly shaped, failing rather than treating malformed data as a
disabled gate; apply these changes at frontend/e2e/fixtures/index.ts lines 63-79
and 83-105.

Source: Path instructions

await use();
},

requireFeatureGate: async ({ k8sClient }, use) => {
await use(async (gateName: string) => {
let enabled: string[] = [];
try {
const fg = await k8sClient.getClusterCustomResource(
'config.openshift.io',
'v1',
'featuregates',
'cluster',
);
const featureSet: string = (fg as any)?.spec?.featureSet ?? '';
const sections: any[] = (fg as any)?.status?.featureGates ?? [];
const section = sections.find((s: any) => s.featureSet === featureSet);
enabled = (section?.enabled ?? []).map((g: any) => String(g.name));
} catch (err) {
throw new Error(
`requireFeatureGate('${gateName}'): could not read FeatureGate CR 'cluster': ${err}`,
);
}
test.skip(
!enabled.includes(gateName),
`Feature gate '${gateName}' is not enabled on this cluster`,
);
});
},

cleanup: async ({}, use, testInfo) => {
const testName = testInfo.titlePath.join(' > ');
const fixture = createCleanupFixture(testName);
Expand Down
13 changes: 13 additions & 0 deletions frontend/e2e/tests/olm/olmv1-catalog.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { test, expect } from '../../fixtures';

test.describe('OLMv1 Software Catalog', { tag: ['@admin', '@tech-preview'] }, () => {
test('Software Catalog page is accessible on TechPreview clusters', async ({
page,
techPreviewOnly,
}) => {
await page.goto('/');
await expect(page).toHaveURL(/\/k8s\/cluster\/clusterserviceversions|\/software-catalog/, {
timeout: 30_000,
Comment on lines +9 to +10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- target file ---'
sed -n '1,120p' frontend/e2e/tests/olm/olmv1-catalog.spec.ts | cat -n

echo
echo '--- similar URL assertions in frontend/e2e/tests/olm ---'
rg -n "toHaveURL\\(" frontend/e2e/tests/olm -S

Repository: openshift/console

Length of output: 884


Constrain the URL regex. Group the alternation and anchor it to the route boundary/end of URL so only /k8s/cluster/clusterserviceversions or /software-catalog matches here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/e2e/tests/olm/olmv1-catalog.spec.ts` around lines 9 - 10, Update the
URL assertion in the OLM catalog test to group the route alternatives and anchor
the regex at the route boundary or URL end, allowing only
/k8s/cluster/clusterserviceversions or /software-catalog matches while
preserving the existing timeout.

Source: Path instructions

});
});
});
19 changes: 19 additions & 0 deletions frontend/integration-tests/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
root: true,
env: {
'cypress/globals': true,
node: true,
},
extends: ['plugin:cypress/recommended'],
plugins: ['cypress'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
ecmaVersion: 2018,
Comment on lines +9 to +13

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

rg -n "sourceType|export function" frontend/integration-tests/.eslintrc.cjs frontend/integration-tests/support/tech-preview-guard.ts

Repository: openshift/console

Length of output: 276


Configure ESLint for module syntax. tech-preview-guard.ts exports requireFeatureGate, but this config still parses the file as a script. Add parserOptions.sourceType: 'module' so ESLint can handle the export syntax.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/integration-tests/.eslintrc.cjs` around lines 9 - 13, Update the
parserOptions configuration in the ESLint config to set sourceType to module,
allowing the exported requireFeatureGate symbol in tech-preview-guard.ts to
parse correctly while preserving the existing parser and project settings.

},
rules: {
'no-console': 'off',
'cypress/unsafe-to-chain-command': 'off',
},
};
39 changes: 39 additions & 0 deletions frontend/integration-tests/support/tech-preview-guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Cypress support helpers for TechPreview and per-feature-gate guards.
*
* Usage (in a Cypress package's support entry point):
*
* // Skip entire suite unless cluster is TechPreviewNoUpgrade:
* import './tech-preview-guard';
*
* // Skip entire suite unless a specific feature gate is enabled:
* import { requireFeatureGate } from './tech-preview-guard';
* requireFeatureGate('OLMv1');
*/

before(function () {
cy.exec('oc get featuregate cluster -o jsonpath={.spec.featureSet}', {
failOnNonZeroExit: false,
}).then((result) => {
if (result.stdout.trim() !== 'TechPreviewNoUpgrade') {
this.skip();
}
});
Comment on lines +14 to +21

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -e
git ls-files frontend/integration-tests/support/tech-preview-guard.ts
wc -l frontend/integration-tests/support/tech-preview-guard.ts
cat -n frontend/integration-tests/support/tech-preview-guard.ts

Repository: openshift/console

Length of output: 1686


🏁 Script executed:

set -e
rg -n "requireFeatureGate|tech-preview-guard|failOnNonZeroExit" frontend/integration-tests -S

Repository: openshift/console

Length of output: 775


🌐 Web query:

Cypress cy.exec failOnNonZeroExit false result.code stdout documentation

💡 Result:

When using cy.exec in Cypress, setting the option failOnNonZeroExit to false prevents the test from failing if the executed command returns a non-zero exit code [1][2]. The cy.exec command yields an object that allows you to inspect the results of the command. As of Cypress v15, this result object includes the following key properties [2][3]: exitCode: The numeric exit code returned by the command (formerly named code in older versions) [3]. stdout: The standard output string from the command [2]. stderr: The standard error string from the command [2]. Example usage: cy.exec('your-command', { failOnNonZeroExit: false }).then((result) => { // Use result.exitCode to check if the command succeeded or failed expect(result.exitCode).to.eq(1); // Use result.stdout or result.stderr to verify output cy.log(result.stdout); }); Note: If you are upgrading from an older version of Cypress, ensure you use exitCode, as the code property was renamed in v15 [3]. The command must still eventually exit, or it will time out according to the configured execTimeout [1][2].

Citations:


Surface oc failures instead of skipping the suite. Both hooks ignore the exit status. If oc get featuregate fails, failOnNonZeroExit: false can turn an infrastructure problem into this.skip(). Check result.exitCode (or result.code on older Cypress) and fail before skipping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/integration-tests/support/tech-preview-guard.ts` around lines 14 -
21, Update the before hook around cy.exec for the featuregate lookup to inspect
result.exitCode, falling back to result.code for older Cypress versions, and
fail immediately when the command fails. Only call this.skip() after a
successful command whose trimmed stdout is not TechPreviewNoUpgrade; apply the
same handling to both hooks if the file contains another equivalent oc check.

});

export function requireFeatureGate(gateName: string): void {
before(function () {
cy.exec(
"oc get featuregate cluster -o jsonpath='{range .status.featureGates[*]}{range .enabled[*]}{.name}{\"\\n\"}{end}{end}'",
{ failOnNonZeroExit: false },
).then((result) => {
const enabled = result.stdout
.split('\n')
.map((s) => s.trim())
.filter(Boolean);
if (!enabled.includes(gateName)) {
this.skip();
}
});
});
}
Loading