Skip to content

🌱 fix: stabilize flaky coverage suite tests (shards 3/6/11)#21299

Merged
clubanderson merged 4 commits into
mainfrom
scanner/fix-21297
Jul 20, 2026
Merged

🌱 fix: stabilize flaky coverage suite tests (shards 3/6/11)#21299
clubanderson merged 4 commits into
mainfrom
scanner/fix-21297

Conversation

@clubanderson

Copy link
Copy Markdown
Collaborator

Fixes #21297
Fixes #21298

Summary

  • Stabilize CreateNamespaceModal tests by explicitly selecting a cluster before submit and aligning the initial-state assertion with the placeholder-selected UI.
  • Stabilize CanIChecker tests by resetting shared mock hook state between tests, accounting for the disabled cluster placeholder option, and selecting a cluster before permission checks.
  • Stabilize NamespaceAccessPanel by asserting the mocked API URL argument directly now that api.get also receives an AbortSignal options object.

Build, lint, and Vitest were not run locally per task instructions; CI validates the PR.

Signed-off-by: Scanner <scanner@kubestellar.io>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 20, 2026 00:05
@kubestellar-prow kubestellar-prow Bot added the size/M Denotes a PR that changes 30-99 lines, ignoring generated files. label Jul 20, 2026
@netlify

netlify Bot commented Jul 20, 2026

Copy link
Copy Markdown

Deploy Preview for kubestellarconsole ready!

Name Link
🔨 Latest commit 8e5c1b4
🔍 Latest deploy log https://app.netlify.com/projects/kubestellarconsole/deploys/6a5dd7aadea78500096e82e9
😎 Deploy Preview https://deploy-preview-21299.console-deploy-preview.kubestellar.io
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

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.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Stabilizes a set of flaky UI tests by making cluster selection explicit, resetting shared mock state consistently, and adjusting expectations to match updated component behavior (placeholder options and api.get signature).

Changes:

  • CanIChecker tests: reset shared mock state per test and require explicit cluster selection; update initial cluster placeholder assertions.
  • CreateNamespaceModal tests: align initial cluster state with placeholder UI and select a cluster before submitting.
  • NamespaceAccessPanel tests: assert directly on the api.get URL argument now that an options object is also passed.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
web/src/components/rbac/tests/CanIChecker.test.tsx Resets shared mock state between tests and updates cluster-selection expectations to reduce flakiness.
web/src/components/namespaces/tests/NamespaceAccessPanel.test.tsx Updates api.get assertion to account for an additional options argument.
web/src/components/namespaces/tests/CreateNamespaceModal.test.tsx Updates initial cluster placeholder expectation and explicitly selects a cluster before create flows.

Comment on lines +293 to +295
// Verify first call with original namespace. api.get also receives an
// AbortSignal options object, so assert against the URL argument directly.
expect(vi.mocked(api.get).mock.calls[0]?.[0]).toContain('test-namespace')
Comment on lines +127 to 132
const clusterSelect = screen.getAllByRole('combobox')[0]
const createBtn = screen.getByRole('button', { name: /create/i })

await user.selectOptions(clusterSelect, 'cluster-1')
await user.type(nameInput, 'test-ns')
await user.type(teamInput, 'my-team')
@github-actions

Copy link
Copy Markdown
Contributor

🐝 Hi @clubanderson! I'm kubestellar-hive[bot], an automation bot for this repo.

Trusted users — org members and contributors with write access — can mention @kubestellar-hive in a comment to trigger repo automation.
On issues, that mention queues an automated fix attempt. On pull requests, it records extra context for existing automation.
This is not an interactive Q&A bot, so mentions should be treated as requests for automation rather than a conversation.

Automation may take a moment to start, and follow-up happens through workflow activity rather than chat replies.

@github-actions github-actions Bot added the ai-generated Pull request generated by AI label Jul 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

👋 Hey @clubanderson — thanks for opening this PR!

🤖 This project is developed exclusively using AI coding assistants.

Please do not attempt to code anything for this project manually.
All contributions should be authored using an AI coding tool such as:

This ensures consistency in code style, architecture patterns, test coverage,
and commit quality across the entire codebase.


This is an automated message.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Test Coverage Check

All new source files in this PR have corresponding test files.

Checked web/src/hooks/ and web/src/components/ against origin/main.

@github-actions

Copy link
Copy Markdown
Contributor

♿ Accessibility Audit (WCAG 2.1 AA)

✅ No WCAG 2.1 AA violations detected in audited routes.


Powered by axe-core. Target: WCAG 2.1 AA compliance.

@clubanderson clubanderson left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[quality] LGTM with observations (comment mode; self-approve blocked)

Correct diagnosis on all three files. Notes:

NamespaceAccessPanel — good learning from #21282

The comment api.get also receives an AbortSignal options object, so assert against the URL argument directly is exactly the right explanation. Important: this invalidates a suggestion I gave on #21282: I recommended toHaveBeenLastCalledWith(expect.stringContaining(...)) as more idiomatic, but that matcher has the same problem — it requires ALL args to match, so it fails when the mock is called as (url, {signal}). Your vi.mocked(api.get).mock.calls[0]?.[0] pattern is correct here. Kudos.

But: the sibling assertion I flagged in the previous review is still in the file — expect(api.get).toHaveBeenCalledTimes(2) at the bottom of the same test. Now that you've made the switch to direct array indexing for the first-call check, the same pattern belongs on the last-call check too. Consider:

expect(vi.mocked(api.get).mock.calls).toHaveLength(2)
expect(vi.mocked(api.get).mock.calls[1]?.[0]).toContain('another-namespace')

Not blocking this PR, but a quick follow-up would eliminate the second mock.calls[length-1] variant added in #21282.

CreateNamespaceModal — placeholder default is safe, but untested

I verified CreateNamespaceModal.tsx: handleCreate guards if (!name || !cluster) return and the Create button has disabled={!name || !cluster || creating}, so the new value === '' default is safe — user can't submit with placeholder still selected. Good defensive design.

But: there is no test that locks this. The renamed test initializes with cluster placeholder selected verifies the initial value, not the behavior when submitting with empty cluster. Suggest adding:

it('disables Create button when no cluster selected', () => {
  render(<CreateNamespaceModal clusters={clusters} onClose={vi.fn()} onCreated={vi.fn()} />)
  const createBtn = screen.getByRole('button', { name: /create/i })
  expect(createBtn).toBeDisabled()
})

it('does not call onCreated when submit fires with no cluster', async () => {
  const onCreated = vi.fn()
  render(<CreateNamespaceModal clusters={clusters} onClose={vi.fn()} onCreated={onCreated} />)
  await user.type(screen.getByPlaceholderText('my-namespace'), 'test-ns')
  // Try to click anyway (button is disabled but let's verify guard fires too)
  fireEvent.click(screen.getByRole('button', { name: /create/i }))
  expect(onCreated).not.toHaveBeenCalled()
})

If this behavior ever regresses (e.g., someone accidentally removes the guard), 6 downstream tests still pass because they all selectOptions('cluster-1') first. The guard becomes untested.

CanIChecker — clean pattern

  • Top-level beforeEach with fresh [...defaultMockClusters] spreads is a nice defensive copy pattern (prevents test-mutation cross-contamination). Good.
  • selectCluster helper is clean; called 20+ times where needed.
  • One inconsistency: selectCluster uses fireEvent.change, while CreateNamespaceModal.test.tsx uses user.selectOptions. Same file suite, two different testing-library patterns. Not blocking, but worth aligning long-term.
  • Options-length expectation flip (2 → 3, accounting for placeholder) is correct.

AbortSignal coverage gap (non-blocking follow-up)

The comment mentions api.get also receives an AbortSignal options object, but I don't see any test that verifies:

  • The signal is actually passed
  • The fetch aborts when the namespace changes (which is presumably why the signal was added in the first place)

If the intent is "cancel in-flight fetches on rerender", a targeted test is worth adding:

it('aborts previous fetch when namespace prop changes', async () => {
  render(<NamespaceAccessPanel namespace={mockNamespace} />)
  const firstSignal = vi.mocked(api.get).mock.calls[0]?.[1]?.signal
  rerender(<NamespaceAccessPanel namespace={newNamespace} />)
  await waitFor(() => expect(firstSignal?.aborted).toBe(true))
})

Bead filed. Not merging.


Filed by quality agent (ACMM L4/L6 — full mode)

Signed-off-by: Scanner Bot <scanner@kubestellar.io>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Jul 20, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign mikespreitzer for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copilot and others added 2 commits July 20, 2026 03:12
The afterEach block that restored mockClusters was removed in a
prior commit, leaving afterEach imported but unused — triggering
@typescript-eslint/no-unused-vars in the lint baseline check.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Copilot <copilot@github.com>
@clubanderson
clubanderson merged commit f355883 into main Jul 20, 2026
30 of 32 checks passed
@kubestellar-prow
kubestellar-prow Bot deleted the scanner/fix-21297 branch July 20, 2026 08:09
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

Check out what's new:

Stay connected: Slack #kubestellar-dev | Multi-Cluster Survey

@github-actions

Copy link
Copy Markdown
Contributor

✅ Post-Merge Verification: passed

Commit: f3558831c183e346bed2e1326a4464c180e41a1f
Specs run: NamespaceOverview.spec.ts smoke.spec.ts
Report: https://github.com/kubestellar/console/actions/runs/29726922820

@github-actions

Copy link
Copy Markdown
Contributor

Post-merge build verification passed

Both Go and frontend builds compiled successfully against merge commit f3558831c183e346bed2e1326a4464c180e41a1f.

@github-actions

Copy link
Copy Markdown
Contributor

❌ Playwright Tests Failed

📊 View Full Report

Download the playwright-report artifact from the workflow run for screenshots and detailed traces.

To view the report locally:

# Download and extract playwright-report.zip
npx playwright show-report path/to/playwright-report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-generated Pull request generated by AI dco-signoff: yes Indicates the PR's author has signed the DCO. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. tier/1-lightweight

Projects

None yet

2 participants