Preserve live scope across evidence and registry flows

This commit is contained in:
master
2026-03-09 22:11:08 +02:00
parent dfd22281ed
commit 3ecafc49a3
7 changed files with 104 additions and 1 deletions

View File

@@ -83,6 +83,7 @@ const surfaceConfigs = [
selector: 'main button:has-text("Back to Search")',
expectedUrlPattern: '/evidence/threads',
expectedTextPattern: /evidence threads/i,
requiredUrlFragments: ['tenant=', 'regions='],
},
],
},
@@ -115,6 +116,7 @@ const surfaceConfigs = [
selector: 'a[href*="/registry-admin/audit"], button:has-text("Audit")',
expectedUrlPattern: '/registry-admin/audit',
expectedTextPattern: /audit/i,
requiredUrlFragments: ['tenant=', 'regions='],
},
],
},
@@ -389,7 +391,9 @@ async function verifySurfaceActions(context, surface) {
const bodyText = await collectBodyText(page);
const headingText = firstMatchingHeading(action.expectedTextPattern, headings);
const finalUrl = page.url();
const hasRequiredUrlFragments = (action.requiredUrlFragments ?? []).every((fragment) => finalUrl.includes(fragment));
const ok = finalUrl.includes(action.expectedUrlPattern)
&& hasRequiredUrlFragments
&& matchesPattern(action.expectedTextPattern, headings, bodyText);
results.push({

View File

@@ -89,6 +89,7 @@ describe('EvidenceThreadViewComponent', () => {
expect(router.navigate).toHaveBeenCalledWith(['/evidence/threads'], {
queryParams: { purl: 'pkg:oci/acme/api@sha256:abc123' },
queryParamsHandling: 'merge',
});
});

View File

@@ -87,7 +87,8 @@ export class EvidenceThreadViewComponent implements OnInit, OnDestroy {
onBack(): void {
const purl = this.returnPurl();
void this.router.navigate(['/evidence/threads'], {
queryParams: purl ? { purl } : {},
queryParams: purl ? { purl } : undefined,
queryParamsHandling: 'merge',
});
}

View File

@@ -0,0 +1,40 @@
import { TestBed } from '@angular/core/testing';
import { RouterLink, provideRouter } from '@angular/router';
import { By } from '@angular/platform-browser';
import { of } from 'rxjs';
import { REGISTRY_ADMIN_API } from '../../core/api/registry-admin.client';
import { RegistryAdminComponent } from './registry-admin.component';
describe('RegistryAdminComponent', () => {
const registryAdminApiStub = {
listPlans: () => of([]),
};
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [RegistryAdminComponent],
providers: [
provideRouter([]),
],
})
.overrideComponent(RegistryAdminComponent, {
set: {
providers: [{ provide: REGISTRY_ADMIN_API, useValue: registryAdminApiStub }],
},
})
.compileComponents();
});
it('merges the active query scope across registry admin tabs', () => {
const fixture = TestBed.createComponent(RegistryAdminComponent);
fixture.detectChanges();
const links = fixture.debugElement
.queryAll(By.directive(RouterLink))
.map((debugElement) => debugElement.injector.get(RouterLink));
expect(links.length).toBe(2);
expect(links.every((link) => link.queryParamsHandling === 'merge')).toBeTrue();
});
});

View File

@@ -49,6 +49,7 @@ type TabType = 'plans' | 'audit';
class="registry-admin__tab"
[class.registry-admin__tab--active]="activeTab() === 'plans'"
routerLink="plans"
queryParamsHandling="merge"
role="tab"
[attr.aria-selected]="activeTab() === 'plans'"
>
@@ -58,6 +59,7 @@ type TabType = 'plans' | 'audit';
class="registry-admin__tab"
[class.registry-admin__tab--active]="activeTab() === 'audit'"
routerLink="audit"
queryParamsHandling="merge"
role="tab"
[attr.aria-selected]="activeTab() === 'audit'"
>

View File

@@ -0,0 +1,12 @@
{
"extends": "./tsconfig.spec.json",
"include": [],
"files": [
"src/test-setup.ts",
"src/app/core/api/first-signal.client.spec.ts",
"src/app/core/console/console-status.service.spec.ts",
"src/app/features/policy-simulation/simulation-dashboard.component.spec.ts",
"src/app/features/registry-admin/registry-admin.component.spec.ts",
"src/app/features/evidence-thread/__tests__/evidence-thread-view.component.spec.ts"
]
}