CI / lint (push) Successful in 3s
CI / extension-version (push) Successful in 3s
Build images / sign-extension (push) Successful in 3s
Build images / build-agent (push) Successful in 9s
CI / frontend-build (push) Successful in 21s
CI / backend-lint-and-test (push) Successful in 33s
CI / integration (push) Successful in 2m40s
Build images / build-ml (push) Successful in 2m47s
Build images / build-web (push) Successful in 1m35s
Build images / smoke-web (push) Skipped
Build images / promote (push) Skipped
A3 of milestone 387, completing phase A. A1 made the count true, A2 made it a durable state; this makes it something the operator can see without going looking. Turned out smaller than filed, because A2 revealed why the existing `tier_limited` palette entry in FailingSourcesCard had never rendered: the chip was being cleared by the same successful run that produced it. The colour was already chosen. Where it surfaces: - SourceHealthDot gains a `no-access` grade. Deliberately its own grade rather than folded into healthy (which hides it) or warning (which sends the operator hunting for a break that isn't there). A source with real failures still grades as failing whether or not it is also gated. - SourceRow gets an info-coloured lock chip in the status cell, which was empty for these sources — they have zero failures. Placed ahead of the backfill states: "we can't see this creator" is the more useful thing to say than which walk phase it is in, and unlike those it does not resolve on its own. - A "No access" status filter, deliberately separate from "Has errors". Without it a gated source is invisible in a long list, because it correctly stays out of the failing rollup. Left OUT of NeedsAttentionCard on purpose. That card's only affordance is Retry, and you cannot retry your way into a subscription tier — issue 1285 already gives the real escape hatch, since disabling a source clears its state. Nothing structural needed changing: the card is fed by consecutive_failures > 0, which a tier-limited source never has. The count lives on the download event, not the source, so `list()` joins it in with one DISTINCT ON query — selecting the run_stats sub-object rather than whole metadata blobs, which carry up to 500KB of truncated stdout each. Scoped to tier-gated rows only, so a healthy library issues no extra query at all. Absent stays None rather than 0, and both UI surfaces phrase the state without a number when it is missing instead of printing a fabricated zero. Also covers A1's live gated count, which shipped untested, and extends the mount helper with slot stubs: SourceHealthDot puts the dot in a NAMED slot, and unresolved Vuetify components render default slots only — so those assertions would have found an empty wrapper and passed vacuously. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LNXXULQDjVZmbuNa2G9mD9
38 lines
1.4 KiB
JavaScript
38 lines
1.4 KiB
JavaScript
import { mount } from '@vue/test-utils'
|
|
import { createPinia, setActivePinia } from 'pinia'
|
|
|
|
// Smoke-test helper. Vuetify components are left unresolved (Vue 3 renders
|
|
// unknown elements with their slot children, so text content is still
|
|
// present and nothing throws), which avoids standing up the whole Vuetify
|
|
// plugin in happy-dom. RouterLink is the one import that needs a router, so
|
|
// it's stubbed with a slot-rendering anchor.
|
|
|
|
export function freshPinia () {
|
|
const pinia = createPinia()
|
|
setActivePinia(pinia)
|
|
return pinia
|
|
}
|
|
|
|
// `stubs` is merged over the defaults. Needed whenever the component under
|
|
// test puts content in a NAMED slot of a Vuetify component: leaving those
|
|
// unresolved renders default-slot children only, so a named slot (v-tooltip's
|
|
// `#activator`, say) silently renders nothing and assertions find an empty
|
|
// wrapper rather than failing loudly.
|
|
export function mountComponent (Component, { props = {}, pinia, stubs = {} } = {}) {
|
|
return mount(Component, {
|
|
props,
|
|
global: {
|
|
plugins: pinia ? [pinia] : [],
|
|
stubs: { RouterLink: { template: '<a><slot /></a>' }, ...stubs },
|
|
},
|
|
})
|
|
}
|
|
|
|
// Renders both halves of a v-tooltip: the activator (the thing the operator
|
|
// actually sees) and the tip body. `props` is passed as an empty object so the
|
|
// activator's `v-bind="tipProps"` binds cleanly.
|
|
export const VTooltipStub = {
|
|
name: 'VTooltip',
|
|
template: '<div><slot name="activator" :props="{}" /><slot /></div>',
|
|
}
|