Skip to content

Commit e48c6ac

Browse files
committed
test(acr): cover the new frontend system wiring
The alpha surface had no test. `plugin.test.ts` asserts the legacy plugin is defined, and `AcrImagesEntityContent.test.tsx` renders the component directly, but nothing checked what the entity content declares to the catalog: the tab title, the path it mounts at, the filter deciding which entities show it, or whether the plugin registers the extension at all. Those four are what an end-to-end test is really checking when it opens an annotated entity and clicks the tab. Asserted here they take milliseconds and name the extension when they break, instead of surfacing as a missing heading after a deployment. The registration test is the one that is easy to leave out and the one that matters most. `createExtensionTester` instantiates an extension in isolation, so deleting `acrImagesEntityContent` from the plugin's `extensions` array leaves every other assertion here green — and a plugin that contributes nothing still boots cleanly, so nothing else reports it either. Rendering is deliberately not repeated; the component already has its own test. Each assertion was checked by mutating the source it covers: changing the title, changing the path, replacing the filter with `() => true`, removing the extension from the plugin, and renaming the plugin id each turn exactly one test red. Adds `@backstage/frontend-test-utils` as a devDependency, which the package did not carry. Signed-off-by: Gustavo Lira e Silva <guga.java@gmail.com>
1 parent 4c65ad0 commit e48c6ac

4 files changed

Lines changed: 551 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@backstage-community/plugin-acr': patch
3+
---
4+
5+
Add tests for the new frontend system wiring: the entity content's title, route path and entity filter, and that the plugin registers both extensions. Test-only; no runtime change.

workspaces/acr/plugins/acr/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"@axe-core/playwright": "^4.11.0",
6565
"@backstage/cli": "^0.36.3",
6666
"@backstage/dev-utils": "^1.1.24",
67+
"@backstage/frontend-test-utils": "^0.6.3",
6768
"@backstage/test-utils": "^1.7.19",
6869
"@playwright/test": "1.61.1",
6970
"@testing-library/jest-dom": "6.9.1",
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2025 The Backstage Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { Entity } from '@backstage/catalog-model';
17+
import { coreExtensionData } from '@backstage/frontend-plugin-api';
18+
import { createExtensionTester } from '@backstage/frontend-test-utils';
19+
import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
20+
21+
import { mockEntity } from './__fixtures__/mockEntity';
22+
import nfsPlugin, { acrImagesEntityContent } from './alpha';
23+
24+
/**
25+
* These assert the plugin's *wiring* under the new frontend system: the title the
26+
* catalog will print on the tab, the path it mounts at, and the entities it shows
27+
* for. Under the new frontend system those are declared by the extension rather
28+
* than configured by the app, so an end-to-end test that clicks the tab is really
29+
* checking these three facts through a browser and a deployment.
30+
*
31+
* Rendering is covered a layer down by AcrImagesEntityContent.test.tsx; the only
32+
* render here is through the extension itself, which is the part that test cannot
33+
* reach.
34+
*/
35+
describe('alpha (new frontend system)', () => {
36+
it('declares the tab title the catalog will render', () => {
37+
const tester = createExtensionTester(acrImagesEntityContent);
38+
39+
expect(tester.get(EntityContentBlueprint.dataRefs.title)).toBe(
40+
'ACR images',
41+
);
42+
});
43+
44+
it('declares the path the tab mounts at', () => {
45+
const tester = createExtensionTester(acrImagesEntityContent);
46+
47+
expect(tester.get(coreExtensionData.routePath)).toBe('acr-images');
48+
});
49+
50+
describe('the filter that decides which entities show the tab', () => {
51+
const filter = () => {
52+
const fn = createExtensionTester(acrImagesEntityContent).get(
53+
EntityContentBlueprint.dataRefs.filterFunction,
54+
);
55+
// The blueprint makes this output optional, and an extension without it
56+
// shows the tab on every entity in the catalog — so its absence is a
57+
// defect rather than a variant, and worth failing on by name.
58+
if (!fn)
59+
throw new Error('acrImagesEntityContent declares no entity filter');
60+
return fn;
61+
};
62+
63+
it('shows the tab for an entity annotated with a repository name', () => {
64+
expect(filter()(mockEntity)).toBe(true);
65+
});
66+
67+
it('hides the tab for an entity with no ACR annotation', () => {
68+
const withoutAnnotation: Entity = {
69+
...mockEntity,
70+
metadata: { ...mockEntity.metadata, annotations: {} },
71+
};
72+
73+
expect(filter()(withoutAnnotation)).toBe(false);
74+
});
75+
});
76+
77+
/**
78+
* Not optional, and not covered by any assertion above.
79+
*
80+
* `createExtensionTester` instantiates an extension in isolation, so it cannot
81+
* see whether the plugin actually registers it. Deleting `acrImagesEntityContent`
82+
* from the plugin's `extensions` array leaves every test above green while the
83+
* tab disappears from a real app — and because a plugin that contributes nothing
84+
* still boots cleanly, nothing else would report it either.
85+
*/
86+
describe('registration', () => {
87+
it('registers the entity content and the API on the plugin', () => {
88+
expect(
89+
nfsPlugin.getExtension('entity-content:acr/acrImagesEntityContent'),
90+
).toBeDefined();
91+
expect(nfsPlugin.getExtension('api:acr/acrApi')).toBeDefined();
92+
});
93+
94+
it('is a frontend plugin the app can install, under the expected id', () => {
95+
expect(nfsPlugin.$$type).toBe('@backstage/FrontendPlugin');
96+
expect(nfsPlugin.pluginId).toBe('acr');
97+
});
98+
});
99+
});

0 commit comments

Comments
 (0)