Skip to content

Commit cc35069

Browse files
committed
test(acr): address review — pin to the release manifest, and actually render
Five review findings. @backstage/frontend-test-utils was added as ^0.6.3 while this workspace pins Backstage 1.52.0, whose manifest ships 0.6.1. The caret pulled a second frontend-plugin-api/core-components tree: 446 lines of lockfile and `yarn dedupe --check` reporting 15 dedupable packages, which scripts/ci/verify-lockfile-duplicates.js runs in CI. `^0.6.1` does not help — yarn still resolves to 0.6.3 — so it is pinned exactly, and the lockfile delta drops to 37 lines with a clean dedupe. The file claimed "the only render here is through the extension itself" and then never rendered: reactElement() was never called, so the blueprint's dynamic import was untested and renaming the component left every assertion green. There is now a real render through the extension, and pointing the loader at the wrong component turns exactly one test red. Copyright year corrected to 2026, per AGENTS.md. The changeset described internal test scaffolding; AGENTS.md asks for adopter-facing plain language. Six single-assertion tests consolidated into three thorough ones, per AGENTS.md. The assertion on the plugin's $$type went with them — it is a Backstage-internal marker that no change to this plugin can affect, so it could only ever go red on an unrelated framework upgrade. All six mutations still caught, one test each: title, path, filter, extension removed from the plugin, plugin id renamed, and now the loader's import target. Signed-off-by: Gustavo Lira e Silva <guga.java@gmail.com>
1 parent e48c6ac commit cc35069

4 files changed

Lines changed: 71 additions & 489 deletions

File tree

workspaces/acr/.changeset/acr-alpha-wiring-tests.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
'@backstage-community/plugin-acr': patch
33
---
44

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.
5+
Added tests covering the plugin's new frontend system entity content. No change in behaviour.

workspaces/acr/plugins/acr/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +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",
67+
"@backstage/frontend-test-utils": "0.6.1",
6868
"@backstage/test-utils": "^1.7.19",
6969
"@playwright/test": "1.61.1",
7070
"@testing-library/jest-dom": "6.9.1",
Lines changed: 54 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2025 The Backstage Authors
2+
* Copyright 2026 The Backstage Authors
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,85 +15,76 @@
1515
*/
1616
import { Entity } from '@backstage/catalog-model';
1717
import { coreExtensionData } from '@backstage/frontend-plugin-api';
18-
import { createExtensionTester } from '@backstage/frontend-test-utils';
18+
import {
19+
createExtensionTester,
20+
renderInTestApp,
21+
} from '@backstage/frontend-test-utils';
22+
import { EntityProvider } from '@backstage/plugin-catalog-react';
1923
import { EntityContentBlueprint } from '@backstage/plugin-catalog-react/alpha';
24+
import { screen } from '@testing-library/react';
2025

26+
import { AzureContainerRegistryApiRef } from './api';
27+
import { mockAcrTagsData } from './__fixtures__/acrTagsObject';
2128
import { mockEntity } from './__fixtures__/mockEntity';
2229
import nfsPlugin, { acrImagesEntityContent } from './alpha';
30+
import { TagsResponse } from './types';
31+
32+
/** The fixture carries ISO strings where the API returns Dates. */
33+
const tagsResponse: TagsResponse = {
34+
imageName: mockAcrTagsData.imageName,
35+
registry: mockAcrTagsData.registry,
36+
tags: mockAcrTagsData.tags.map(tag => ({
37+
...tag,
38+
createdTime: new Date(tag.createdTime),
39+
lastUpdateTime: new Date(tag.lastUpdateTime),
40+
})),
41+
};
2342

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-
*/
3543
describe('alpha (new frontend system)', () => {
36-
it('declares the tab title the catalog will render', () => {
44+
it('declares the tab the catalog renders, and which entities get it', () => {
3745
const tester = createExtensionTester(acrImagesEntityContent);
3846

3947
expect(tester.get(EntityContentBlueprint.dataRefs.title)).toBe(
4048
'ACR images',
4149
);
42-
});
43-
44-
it('declares the path the tab mounts at', () => {
45-
const tester = createExtensionTester(acrImagesEntityContent);
46-
4750
expect(tester.get(coreExtensionData.routePath)).toBe('acr-images');
48-
});
4951

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;
52+
const filter = tester.get(EntityContentBlueprint.dataRefs.filterFunction);
53+
if (!filter) throw new Error('the entity content declares no filter');
54+
const withoutAnnotation: Entity = {
55+
...mockEntity,
56+
metadata: { ...mockEntity.metadata, annotations: {} },
6157
};
58+
expect(filter(mockEntity)).toBe(true);
59+
expect(filter(withoutAnnotation)).toBe(false);
60+
});
6261

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-
});
62+
it('is registered by the plugin under the id the app resolves', () => {
63+
// Not covered by anything else here: createExtensionTester instantiates an
64+
// extension in isolation, so removing it from the plugin's `extensions`
65+
// leaves every other assertion in this file green while the tab disappears.
66+
expect(
67+
nfsPlugin.getExtension('entity-content:acr/acrImagesEntityContent'),
68+
).toBeDefined();
69+
expect(nfsPlugin.getExtension('api:acr/acrApi')).toBeDefined();
7570
});
7671

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-
});
72+
it('renders the registry through the extension', async () => {
73+
// Through the blueprint's own loader, which the component's own test cannot
74+
// reach — renaming the component leaves the assertions above green.
75+
renderInTestApp(
76+
<EntityProvider entity={mockEntity}>
77+
{createExtensionTester(acrImagesEntityContent).reactElement()}
78+
</EntityProvider>,
79+
{
80+
apis: [
81+
[AzureContainerRegistryApiRef, { getTags: async () => tagsResponse }],
82+
],
83+
},
84+
);
9385

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-
});
86+
expect(
87+
await screen.findByText(tagsResponse.tags[0].name),
88+
).toBeInTheDocument();
9889
});
9990
});

0 commit comments

Comments
 (0)