Skip to content

Commit e7340c8

Browse files
committed
feat(extensions): migrate to NFS
1 parent 6394d89 commit e7340c8

74 files changed

Lines changed: 3115 additions & 328 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-extensions': minor
3+
---
4+
5+
Migrated plugin to NFS

workspaces/extensions/app-config.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
app:
22
title: Backstage App
33
baseUrl: http://localhost:3000
4+
packages: all
5+
6+
extensions:
7+
- page:catalog:
8+
config:
9+
path: /
10+
- api:app/app-language:
11+
config:
12+
availableLanguages: ['en', 'de', 'es', 'fr', 'it', 'ja']
13+
defaultLanguage: 'en'
14+
- nav-item:user-settings: false
15+
- nav-item:search: false
416

517
organization:
618
name: My Company
@@ -128,6 +140,11 @@ permission:
128140
pluginsWithPermission:
129141
- catalog
130142
- extensions
143+
admin:
144+
superUsers:
145+
- name: user:development/guest
146+
users:
147+
- name: user:development/guest
131148

132149
extensions:
133150
# directory: ../../examples # YAML files are in the examples directory

workspaces/extensions/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
},
88
"scripts": {
99
"start": "backstage-cli repo start",
10+
"start:legacy": "yarn start app-legacy backend",
1011
"start-backend": "yarn workspace backend start",
1112
"build:backend": "yarn workspace backend build",
1213
"tsc": "tsc",
@@ -19,7 +20,10 @@
1920
"clean": "backstage-cli repo clean",
2021
"test": "backstage-cli repo test --detectOpenHandles",
2122
"test:all": "backstage-cli repo test --coverage --detectOpenHandles",
22-
"test:e2e": "playwright test",
23+
"test:legacy": "APP_MODE=legacy playwright test",
24+
"test:nfs": "APP_MODE=nfs playwright test",
25+
"test:e2e:ci": "yarn test:legacy && yarn test:nfs",
26+
"playwright": "sh -c 'if [ \"$1\" = test ] && [ $# -eq 1 ]; then yarn test:e2e:ci; else exec playwright \"$@\"; fi' _",
2327
"fix": "backstage-cli repo fix",
2428
"lint": "backstage-cli repo lint --since origin/main",
2529
"lint:all": "backstage-cli repo lint",
File renamed without changes.
File renamed without changes.
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* Copyright Red Hat, Inc.
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+
17+
import { test, expect, Page, type BrowserContext } from '@playwright/test';
18+
import { Extensions } from './pages/extensions';
19+
import { runAccessibilityTests } from './utils/accessibility';
20+
import { ExtensionHelper } from './utils/helper';
21+
import { ExtensionsMessages, getTranslations } from './utils/translations';
22+
23+
/**
24+
* Mapping of locale codes to their native display names
25+
*/
26+
const LOCALE_DISPLAY_NAMES: Record<string, string> = {
27+
en: 'English',
28+
fr: 'Français',
29+
it: 'Italiano',
30+
ja: '日本語',
31+
};
32+
33+
/**
34+
* Get the display name for a locale code
35+
*/
36+
function getLocaleDisplayName(locale: string): string {
37+
const baseLocale = locale.split('-')[0];
38+
return LOCALE_DISPLAY_NAMES[baseLocale] || locale;
39+
}
40+
41+
test.describe('Admin > Extensions', () => {
42+
let extensions: Extensions;
43+
let extensionHelper: ExtensionHelper;
44+
let translations: ExtensionsMessages;
45+
let sharedPage: Page;
46+
let sharedContext: BrowserContext;
47+
48+
async function switchToLocale(page: Page, locale: string): Promise<void> {
49+
const baseLocale = locale.split('-')[0];
50+
if (baseLocale === 'en') return;
51+
52+
const displayName = getLocaleDisplayName(locale);
53+
await page.getByRole('link', { name: 'Settings' }).click();
54+
await page.getByRole('button', { name: 'English' }).click();
55+
await page.getByRole('option', { name: displayName }).click();
56+
await page.locator('a').filter({ hasText: 'Home' }).click();
57+
}
58+
59+
test.beforeAll(async ({ browser }) => {
60+
sharedContext = await browser.newContext();
61+
sharedPage = await sharedContext.newPage();
62+
const currentLocale = await sharedPage.evaluate(
63+
() => globalThis.navigator.language.split('-')[0],
64+
);
65+
await sharedPage.goto('/');
66+
await sharedPage.getByRole('button', { name: 'Enter' }).click();
67+
await switchToLocale(sharedPage, currentLocale);
68+
translations = getTranslations(currentLocale);
69+
extensions = new Extensions(sharedPage, translations);
70+
extensionHelper = new ExtensionHelper(sharedPage, translations);
71+
await extensions.navigateToExtensions(translations.header.extensions);
72+
});
73+
74+
test.afterAll(async () => {
75+
await sharedContext.close();
76+
});
77+
78+
test.describe('Extensions > Catalog', () => {
79+
test('Verify search bar in extensions', async ({ browser: _browser }) => {
80+
await extensionHelper.searchInputPlaceholder('Bulk import');
81+
await extensionHelper.verifyHeading('Bulk import');
82+
});
83+
84+
test('Verify category and author filters in extensions', async ({
85+
browser: _browser,
86+
}, testInfo) => {
87+
await runAccessibilityTests(sharedPage, testInfo);
88+
await extensionHelper.clickTab(translations.header.catalog);
89+
await extensions.selectDropdown(translations.search.category);
90+
await extensionHelper.clickButton('CI/CD');
91+
await sharedPage.keyboard.press(`Escape`);
92+
await extensions.selectDropdown(translations.search.author);
93+
await extensions.toggleOption('Red Hat');
94+
await sharedPage.keyboard.press(`Escape`);
95+
await extensionHelper.verifyHeading('APIs with 3scale');
96+
await extensionHelper.verifyTextInLocator(
97+
'',
98+
`${translations.metadata.by} Red Hat`,
99+
true,
100+
);
101+
102+
await extensionHelper.clickHeading('APIs with 3scale');
103+
await extensionHelper.verifyTableHeadingAndRows([
104+
translations.table.packageName,
105+
translations.table.version,
106+
translations.table.role,
107+
translations.table.status,
108+
]);
109+
await extensionHelper.verifyHeading(translations.metadata.versions);
110+
await extensionHelper.closeBar('Close');
111+
112+
await extensionHelper.clickLink(translations.common.readMore);
113+
await extensionHelper.closeBar('Close');
114+
await extensions.selectDropdown(`${translations.search.author}`);
115+
await extensions.toggleOption('Red Hat');
116+
await extensions.notChecked('Red Hat');
117+
await extensions.emptyCategoryComboBox();
118+
await sharedPage.keyboard.press(`Escape`);
119+
});
120+
121+
test('Verify support type filters in extensions', async ({
122+
browser: _browser,
123+
}) => {
124+
await extensions.selectDropdown(`${translations.search.supportType}`);
125+
await extensions.supportFilters();
126+
await extensions.emptyCategoryComboBox();
127+
});
128+
129+
test('Verify certified badge in extensions', async ({
130+
browser: _browser,
131+
}) => {
132+
await extensions.selectDropdown(`${translations.search.supportType}`);
133+
await extensions.toggleOption(translations.badges.certified);
134+
await sharedPage.keyboard.press(`Escape`);
135+
await extensionHelper.verifyHeading('Certified Plugin ');
136+
await expect(extensions.badge.first()).toBeVisible();
137+
await extensions.badge.first().hover();
138+
await extensionHelper.verifyHeading('Certified Plugin ');
139+
await extensionHelper.clickHeading('Certified Plugin ');
140+
await extensionHelper.closeBar('Close');
141+
await extensionHelper.clickLink(translations.common.readMore);
142+
await extensionHelper.verifyTextInLocator(
143+
'',
144+
translations.metadata.about,
145+
true,
146+
);
147+
await extensionHelper.verifyHeading(translations.metadata.versions);
148+
await extensionHelper.verifyTableHeadingAndRows([
149+
translations.table.packageName,
150+
translations.table.version,
151+
translations.table.role,
152+
translations.table.status,
153+
]);
154+
await extensionHelper.closeBar('Close');
155+
await extensions.resetSupportTypeFilter(translations.badges.certified);
156+
});
157+
158+
test('Verify Generally available badge in extensions', async ({
159+
browser: _browser,
160+
}) => {
161+
await extensions.selectSupportTypeFilter(
162+
translations.badges.generallyAvailable,
163+
);
164+
165+
await expect(extensions.badge.first()).toBeVisible();
166+
await extensions.badge.first().hover();
167+
await extensions.tooltipView(
168+
translations.badges.gaAndSupportedBy.replace(
169+
'{{provider}}',
170+
'A provider',
171+
),
172+
sharedPage,
173+
);
174+
await extensionHelper.clickLink({ href: '/support-generally-available' });
175+
176+
await extensionHelper.labelTextContentVisible(
177+
translations.badges.productionReadyBy.replace(
178+
'{{provider}}',
179+
'A provider',
180+
),
181+
translations.badges.generallyAvailable,
182+
);
183+
184+
await extensionHelper.closeBar('Close');
185+
await extensions.resetSupportTypeFilter(
186+
translations.badges.generallyAvailable,
187+
);
188+
});
189+
190+
test('Verify custom plugin badge in extensions', async ({
191+
browser: _browser,
192+
}) => {
193+
await extensions.selectSupportTypeFilter(
194+
translations.badges.customPlugin,
195+
);
196+
await expect(extensions.badge.first()).toBeVisible();
197+
await extensions.badge.first().hover();
198+
await extensions.tooltipView(
199+
translations.badges.customPlugin,
200+
sharedPage,
201+
);
202+
await extensions.clickReadMoreByPluginTitle(
203+
'Pre-installed False',
204+
sharedPage,
205+
);
206+
await extensionHelper.labelTextContentVisible(
207+
translations.badges.addedByAdmin,
208+
translations.badges.customPlugin,
209+
);
210+
211+
await extensionHelper.closeBar('Close');
212+
await extensions.resetSupportTypeFilter(translations.badges.customPlugin);
213+
});
214+
215+
test('Verify tech preview badge in extensions', async ({
216+
browser: _browser,
217+
}) => {
218+
await extensions.verifySupportTypeBadge({
219+
supportType: translations.badges.techPreview,
220+
pluginName: 'Bulk Import',
221+
badgeLabel: translations.badges.pluginInDevelopment,
222+
badgeText: translations.badges.techPreview,
223+
tooltipText: '',
224+
searchTerm: 'Bulk Import',
225+
includeTable: true,
226+
includeAbout: false,
227+
});
228+
});
229+
230+
test('Verify dev preview badge in extensions', async () => {
231+
await extensions.selectSupportTypeFilter(translations.badges.devPreview);
232+
await extensionHelper.verifyHeading('Extensions');
233+
234+
await extensions.verifyPluginDetails({
235+
pluginName: 'Extensions',
236+
badgeLabel: translations.badges.earlyStageExperimental,
237+
badgeText: translations.badges.devPreview,
238+
includeTable: true,
239+
includeAbout: false,
240+
});
241+
242+
await extensions.resetSupportTypeFilter(translations.badges.devPreview);
243+
});
244+
245+
test('Verify community plugin badge in extensions', async ({
246+
browser: _browser,
247+
}) => {
248+
await extensions.selectSupportTypeFilter(
249+
translations.badges.communityPlugin,
250+
);
251+
252+
await extensions.clickReadMoreByPluginTitle('Support Community');
253+
254+
await extensionHelper.verifyTextInLocator(
255+
'',
256+
translations.metadata.about,
257+
true,
258+
);
259+
await extensionHelper.closeBar('Close');
260+
await extensions.resetSupportTypeFilter(
261+
translations.badges.communityPlugin,
262+
);
263+
});
264+
});
265+
266+
test.describe('Extensions > Installed Plugin', () => {
267+
test('Installed packages page', async ({ browser: _browser }, testInfo) => {
268+
await extensionHelper.clickTab(translations.header.installedPackages);
269+
await extensionHelper.verifyHeading(
270+
new RegExp(`${translations.header.installedPackages} \\(\\d+\\)`),
271+
);
272+
await runAccessibilityTests(sharedPage, testInfo);
273+
await extensionHelper.verifyTableHeadings([
274+
translations.installedPackages.table.columns.name,
275+
translations.installedPackages.table.columns.packageName,
276+
translations.installedPackages.table.columns.role,
277+
translations.installedPackages.table.columns.version,
278+
translations.installedPackages.table.columns.actions,
279+
]);
280+
await extensions.tableRowMoversVisible();
281+
});
282+
});
283+
});

0 commit comments

Comments
 (0)