Skip to content

Commit 862c835

Browse files
HusneShabbirHusneShabbir
andauthored
Add e2e tests for homepage cards and customization (#1697)
- Add e2e tests for homepage cards and customization - Fix ReDoS vulnerability in evaluateMessage function - Replace window with globalThis for SonarQube compliance - Restructure beforeAll in test files - Add test utilities for translations and accessibility Co-authored-by: HusneShabbir <[email protected]>
1 parent 43376f1 commit 862c835

File tree

10 files changed

+807
-51
lines changed

10 files changed

+807
-51
lines changed

workspaces/homepage/packages/app/e2e-tests/app.test.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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, BrowserContext, Page } from '@playwright/test';
18+
import { TestUtils } from './utils/testUtils.js';
19+
import { HomePageCustomization } from './pages/homePageCustomization.js';
20+
import { runAccessibilityTests } from './utils/accessibility.js';
21+
22+
test.describe.serial('Dynamic Home Page Customization', () => {
23+
let testUtils: TestUtils;
24+
let homePageCustomization: HomePageCustomization;
25+
let sharedPage: Page;
26+
let sharedContext: BrowserContext;
27+
28+
test.beforeAll(async ({ browser }) => {
29+
sharedContext = await browser.newContext();
30+
sharedPage = await sharedContext.newPage();
31+
testUtils = new TestUtils(sharedPage);
32+
homePageCustomization = new HomePageCustomization(sharedPage);
33+
await testUtils.loginAsGuest();
34+
});
35+
36+
test.afterAll(async () => {
37+
await sharedContext.close();
38+
});
39+
40+
test('Verify Cards Display After Login', async ({
41+
browser: _browser,
42+
}, testInfo) => {
43+
await homePageCustomization.verifyHomePageLoaded();
44+
await homePageCustomization.verifyAllCardsDisplayed();
45+
await homePageCustomization.verifyEditButtonVisible();
46+
await runAccessibilityTests(sharedPage, testInfo);
47+
});
48+
49+
test('Verify All Cards Can Be Resized in Edit Mode', async ({
50+
browser: _browser,
51+
}, testInfo) => {
52+
await homePageCustomization.enterEditMode();
53+
await runAccessibilityTests(sharedPage, testInfo);
54+
await homePageCustomization.resizeAllCards();
55+
await homePageCustomization.exitEditMode();
56+
});
57+
58+
test('Verify Cards Can Be Individually Deleted in Edit Mode', async ({
59+
browser: _browser,
60+
}, testInfo) => {
61+
await homePageCustomization.enterEditMode();
62+
await homePageCustomization.deleteAllCards();
63+
await homePageCustomization.verifyCardsDeleted();
64+
await runAccessibilityTests(sharedPage, testInfo);
65+
});
66+
67+
test('Verify Restore Default Cards', async ({
68+
browser: _browser,
69+
}, testInfo) => {
70+
await homePageCustomization.restoreDefaultCards();
71+
await homePageCustomization.verifyCardsRestored();
72+
await runAccessibilityTests(sharedPage, testInfo);
73+
});
74+
75+
test('Verify All Cards can be Deleted with Clear all Button', async () => {
76+
await homePageCustomization.enterEditMode();
77+
await homePageCustomization.clearAllCardsWithButton();
78+
await homePageCustomization.verifyCardsDeleted();
79+
});
80+
81+
test('Verify Add Widget Button Adds Cards', async () => {
82+
await homePageCustomization.addWidget('OnboardingSection');
83+
await expect(
84+
sharedPage.getByText(/Good (morning|afternoon|evening)/),
85+
).toBeVisible();
86+
87+
await homePageCustomization.addWidget('EntitySection');
88+
await expect(
89+
sharedPage.getByText('Explore Your Software Catalog'),
90+
).toBeVisible();
91+
92+
await homePageCustomization.addWidget('QuickAccessCard');
93+
await expect(sharedPage.getByText('Quick Access')).toBeVisible();
94+
95+
await homePageCustomization.addWidget('TemplateSection');
96+
await expect(sharedPage.getByText('Explore Templates')).toBeVisible();
97+
});
98+
});
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
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, BrowserContext, Page } from '@playwright/test';
18+
import { TestUtils } from './utils/testUtils.js';
19+
import {
20+
HomepageMessages,
21+
evaluateMessage,
22+
getTranslations,
23+
} from './utils/translations.js';
24+
25+
test.describe('Homepage Card Individual Tests', () => {
26+
let testUtils: TestUtils;
27+
let sharedPage: Page;
28+
let sharedContext: BrowserContext;
29+
let translations: HomepageMessages;
30+
31+
test.beforeAll(async ({ browser }) => {
32+
sharedContext = await browser.newContext();
33+
sharedPage = await sharedContext.newPage();
34+
testUtils = new TestUtils(sharedPage);
35+
const currentLocale = await sharedPage.evaluate(
36+
() => globalThis.navigator.language,
37+
);
38+
await testUtils.loginAsGuest();
39+
await testUtils.switchToLocale(currentLocale);
40+
translations = getTranslations(currentLocale);
41+
});
42+
43+
test.afterAll(async () => {
44+
await sharedContext.close();
45+
});
46+
47+
test('Verify Onboarding Card Content and Links', async () => {
48+
const greetingRegex = new RegExp(
49+
`(${translations.onboarding.greeting.goodMorning}|${translations.onboarding.greeting.goodAfternoon}|${translations.onboarding.greeting.goodEvening})`,
50+
);
51+
const greetingHeading = sharedPage.getByText(greetingRegex);
52+
await expect(greetingHeading).toBeVisible();
53+
54+
const actualHeadingText = await greetingHeading.textContent();
55+
const greetingPart = actualHeadingText
56+
? actualHeadingText.split(',')[0].trim()
57+
: translations.onboarding.greeting.goodMorning;
58+
59+
// Single-word greetings use full word, multi-word use first word
60+
const cardHeading = greetingPart.includes(' ')
61+
? greetingPart.split(' ')[0]
62+
: greetingPart;
63+
64+
await testUtils.verifyTextInCard(
65+
cardHeading,
66+
translations.onboarding.getStarted.title,
67+
);
68+
await testUtils.verifyTextInCard(
69+
cardHeading,
70+
translations.onboarding.getStarted.description,
71+
);
72+
await testUtils.verifyLinkInCard(
73+
cardHeading,
74+
translations.onboarding.getStarted.buttonText,
75+
false,
76+
);
77+
await testUtils.verifyLinkURLInCard(
78+
cardHeading,
79+
translations.onboarding.getStarted.buttonText,
80+
'docs.redhat.com',
81+
false,
82+
);
83+
84+
await testUtils.verifyTextInCard(
85+
cardHeading,
86+
translations.onboarding.explore.title,
87+
);
88+
await testUtils.verifyTextInCard(
89+
cardHeading,
90+
translations.onboarding.explore.description,
91+
);
92+
await testUtils.verifyLinkInCard(
93+
cardHeading,
94+
translations.onboarding.explore.buttonText,
95+
false,
96+
);
97+
await testUtils.verifyLinkURLInCard(
98+
cardHeading,
99+
translations.onboarding.explore.buttonText,
100+
'/catalog',
101+
false,
102+
);
103+
104+
await testUtils.verifyTextInCard(
105+
cardHeading,
106+
translations.onboarding.learn.title,
107+
);
108+
await testUtils.verifyTextInCard(
109+
cardHeading,
110+
translations.onboarding.learn.description,
111+
);
112+
await testUtils.verifyLinkInCard(
113+
cardHeading,
114+
translations.onboarding.learn.buttonText,
115+
false,
116+
);
117+
await testUtils.verifyLinkURLInCard(
118+
cardHeading,
119+
translations.onboarding.learn.buttonText,
120+
'/learning-paths',
121+
false,
122+
);
123+
});
124+
125+
test('Verify Quick Access Card Content and Error State', async () => {
126+
await testUtils.verifyText(translations.quickAccess.title);
127+
128+
await testUtils.verifyTextInCard(
129+
translations.quickAccess.title,
130+
translations.quickAccess.fetchError,
131+
false,
132+
);
133+
});
134+
135+
test('Verify Entities Card Content and Links', async () => {
136+
await testUtils.verifyText(translations.entities.title);
137+
138+
await testUtils.verifyTextInCard(
139+
translations.entities.title,
140+
translations.entities.description,
141+
);
142+
143+
await testUtils.verifyLinkInCard(
144+
translations.entities.title,
145+
evaluateMessage(translations.entities.viewAll, '4'),
146+
);
147+
});
148+
149+
test('Verify Templates Card Content and Links', async () => {
150+
await testUtils.verifyText(translations.templates.title);
151+
152+
await testUtils.verifyTextInCard(
153+
translations.templates.title,
154+
translations.templates.empty,
155+
);
156+
await testUtils.verifyTextInCard(
157+
translations.templates.title,
158+
translations.templates.emptyDescription,
159+
);
160+
161+
await testUtils.verifyLinkInCard(
162+
translations.templates.title,
163+
translations.templates.register,
164+
);
165+
await testUtils.verifyLinkURLInCard(
166+
translations.templates.title,
167+
translations.templates.register,
168+
'/catalog-import',
169+
);
170+
});
171+
});

0 commit comments

Comments
 (0)