mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-08-31 01:14:08 +08:00
test: move internet presence coverage to client (#68362)
Co-authored-by: sembauke <sembauke@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { User } from '../../../redux/prop-types';
|
||||
import Internet from './internet';
|
||||
|
||||
const baseUser = {
|
||||
githubProfile: '',
|
||||
linkedin: '',
|
||||
twitter: '',
|
||||
bluesky: '',
|
||||
website: ''
|
||||
} as User;
|
||||
|
||||
const socialFields = [
|
||||
{
|
||||
label: 'GitHub',
|
||||
url: 'https://github.com/certified-user',
|
||||
checkTestId: 'internet-github-check'
|
||||
},
|
||||
{
|
||||
label: 'LinkedIn',
|
||||
url: 'https://www.linkedin.com/in/certified-user',
|
||||
checkTestId: 'internet-linkedin-check'
|
||||
},
|
||||
{
|
||||
label: 'X',
|
||||
url: 'https://x.com/certified-user',
|
||||
checkTestId: 'internet-twitter-check'
|
||||
},
|
||||
{
|
||||
label: 'Bluesky',
|
||||
url: 'https://bsky.app/profile/certified-user.bsky.social',
|
||||
checkTestId: 'internet-bluesky-check'
|
||||
},
|
||||
{
|
||||
label: 'settings.labels.personal',
|
||||
url: 'https://certified-user.com',
|
||||
checkTestId: 'internet-website-check'
|
||||
}
|
||||
];
|
||||
|
||||
function makeStore() {
|
||||
return configureStore({
|
||||
reducer: (state: Record<string, never> = {}) => state
|
||||
});
|
||||
}
|
||||
|
||||
function renderInternet(userOverrides: Partial<User> = {}) {
|
||||
const store = makeStore();
|
||||
|
||||
return render(
|
||||
<Provider store={store}>
|
||||
<Internet
|
||||
setIsEditing={vi.fn()}
|
||||
user={{ ...baseUser, ...userOverrides }}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
describe('<Internet />', () => {
|
||||
it('renders the internet presence form with a disabled save button', () => {
|
||||
renderInternet();
|
||||
|
||||
expect(
|
||||
screen.getByRole('heading', { name: 'settings.headings.internet' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('group', { name: 'settings.headings.internet' })
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByRole('button', { name: /buttons\.save/ })
|
||||
).toHaveAttribute('aria-disabled', 'true');
|
||||
|
||||
socialFields.forEach(({ checkTestId }) => {
|
||||
expect(screen.queryByTestId(checkTestId)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows a checkmark for each valid social URL', async () => {
|
||||
const user = userEvent.setup();
|
||||
renderInternet();
|
||||
|
||||
for (const { label, url, checkTestId } of socialFields) {
|
||||
await user.type(screen.getByRole('textbox', { name: label }), url);
|
||||
|
||||
expect(screen.getByTestId(checkTestId)).toBeInTheDocument();
|
||||
}
|
||||
|
||||
expect(
|
||||
screen.getByRole('button', { name: /buttons\.save/ })
|
||||
).not.toHaveAttribute('aria-disabled', 'true');
|
||||
});
|
||||
});
|
||||
@@ -154,7 +154,7 @@ const InternetSettings = ({
|
||||
<form
|
||||
id='internet-presence'
|
||||
onSubmit={handleSubmit}
|
||||
data-playwright-test-label='internet-presence'
|
||||
data-testid='internet-presence'
|
||||
>
|
||||
<div role='group' aria-label={t('settings.headings.internet')}>
|
||||
<FormGroup
|
||||
@@ -165,7 +165,7 @@ const InternetSettings = ({
|
||||
GitHub
|
||||
</ControlLabel>
|
||||
<FormControl
|
||||
data-playwright-test-label='internet-github-input'
|
||||
data-testid='internet-github-input'
|
||||
onChange={createHandleChange('githubProfile')}
|
||||
placeholder='https://github.com/user-name'
|
||||
type='url'
|
||||
@@ -175,7 +175,7 @@ const InternetSettings = ({
|
||||
<Check
|
||||
url={formValues.githubProfile}
|
||||
validation={githubProfileValidation}
|
||||
dataPlaywrightTestLabel='internet-github-check'
|
||||
dataTestId='internet-github-check'
|
||||
/>
|
||||
<Info message={githubProfileValidationMessage} />
|
||||
</FormGroup>
|
||||
@@ -196,7 +196,7 @@ const InternetSettings = ({
|
||||
<Check
|
||||
url={formValues.linkedin}
|
||||
validation={linkedinValidation}
|
||||
dataPlaywrightTestLabel='internet-linkedin-check'
|
||||
dataTestId='internet-linkedin-check'
|
||||
/>
|
||||
<Info message={linkedinValidationMessage} />
|
||||
</FormGroup>
|
||||
@@ -215,7 +215,7 @@ const InternetSettings = ({
|
||||
<Check
|
||||
url={formValues.twitter}
|
||||
validation={twitterValidation}
|
||||
dataPlaywrightTestLabel='internet-twitter-check'
|
||||
dataTestId='internet-twitter-check'
|
||||
/>
|
||||
<Info message={twitterValidationMessage} />
|
||||
</FormGroup>
|
||||
@@ -236,7 +236,7 @@ const InternetSettings = ({
|
||||
<Check
|
||||
url={formValues.bluesky}
|
||||
validation={blueskyValidation}
|
||||
dataPlaywrightTestLabel='internet-bluesky-check'
|
||||
dataTestId='internet-bluesky-check'
|
||||
/>
|
||||
<Info message={blueskyValidationMessage} />
|
||||
</FormGroup>
|
||||
@@ -257,7 +257,7 @@ const InternetSettings = ({
|
||||
<Check
|
||||
url={formValues.website}
|
||||
validation={websiteValidation}
|
||||
dataPlaywrightTestLabel='internet-website-check'
|
||||
dataTestId='internet-website-check'
|
||||
/>
|
||||
<Info message={websiteValidationMessage} />
|
||||
</FormGroup>
|
||||
@@ -279,20 +279,16 @@ const InternetSettings = ({
|
||||
const Check = ({
|
||||
url,
|
||||
validation,
|
||||
dataPlaywrightTestLabel
|
||||
dataTestId
|
||||
}: {
|
||||
url: string;
|
||||
validation: URLValidation['state'];
|
||||
dataPlaywrightTestLabel: string;
|
||||
dataTestId: string;
|
||||
}) =>
|
||||
url && validation === 'success' ? (
|
||||
<FormControl.Feedback>
|
||||
<span>
|
||||
<FontAwesomeIcon
|
||||
data-playwright-test-label={dataPlaywrightTestLabel}
|
||||
icon={faCheck}
|
||||
size='1x'
|
||||
/>
|
||||
<FontAwesomeIcon data-testid={dataTestId} icon={faCheck} size='1x' />
|
||||
</span>
|
||||
</FormControl.Feedback>
|
||||
) : null;
|
||||
|
||||
@@ -3,16 +3,11 @@ import { test, expect } from '@playwright/test';
|
||||
import translations from '../client/i18n/locales/english/translations.json';
|
||||
|
||||
const settingsPageElement = {
|
||||
githubInput: 'internet-github-input',
|
||||
githubCheckmark: 'internet-github-check',
|
||||
linkedinCheckmark: 'internet-linkedin-check',
|
||||
twitterCheckmark: 'internet-twitter-check',
|
||||
blueskyCheckmark: 'internet-bluesky-check',
|
||||
personalWebsiteCheckmark: 'internet-website-check',
|
||||
flashMessageAlert: 'flash-message',
|
||||
internetPresenceForm: 'internet-presence'
|
||||
} as const;
|
||||
|
||||
const githubUrl = 'https://github.com/certified-user';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Reset input values
|
||||
execSync('node ../tools/scripts/seed/seed-demo-user --certified-user');
|
||||
@@ -24,7 +19,8 @@ test.beforeEach(async ({ page }) => {
|
||||
|
||||
test.describe('Your Internet Presence', () => {
|
||||
test.skip(({ browserName }) => browserName === 'webkit', 'flaky on Safari');
|
||||
test('should display the section with save button being disabled', async ({
|
||||
|
||||
test('should save a social link and keep it after reload', async ({
|
||||
page
|
||||
}) => {
|
||||
await expect(
|
||||
@@ -34,69 +30,24 @@ test.describe('Your Internet Presence', () => {
|
||||
})
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page
|
||||
.getByTestId(settingsPageElement.internetPresenceForm)
|
||||
.getByRole('button', { name: translations.buttons.save })
|
||||
).toBeVisible();
|
||||
});
|
||||
const socialInput = page.getByRole('textbox', { name: 'GitHub' });
|
||||
await expect(socialInput).toBeVisible();
|
||||
await socialInput.fill(githubUrl);
|
||||
|
||||
const socials = [
|
||||
{
|
||||
name: 'github',
|
||||
url: 'https://github.com/certified-user',
|
||||
label: 'GitHub',
|
||||
checkTestId: settingsPageElement.githubCheckmark
|
||||
},
|
||||
{
|
||||
name: 'linkedin',
|
||||
url: 'https://www.linkedin.com/in/certified-user',
|
||||
label: 'LinkedIn',
|
||||
checkTestId: settingsPageElement.linkedinCheckmark
|
||||
},
|
||||
{
|
||||
name: 'twitter',
|
||||
url: 'https://x.com/certified-user',
|
||||
label: 'X',
|
||||
checkTestId: settingsPageElement.twitterCheckmark
|
||||
},
|
||||
{
|
||||
name: 'bluesky',
|
||||
url: 'https://bsky.app/profile/certified-user.bsky.social',
|
||||
label: 'Bluesky',
|
||||
checkTestId: settingsPageElement.blueskyCheckmark
|
||||
},
|
||||
{
|
||||
name: 'website',
|
||||
url: 'https://certified-user.com',
|
||||
label: translations.settings.labels.personal,
|
||||
checkTestId: settingsPageElement.personalWebsiteCheckmark
|
||||
}
|
||||
];
|
||||
const saveButton = page
|
||||
.locator(`[data-testid="${settingsPageElement.internetPresenceForm}"]`)
|
||||
.getByRole('button', { name: translations.buttons.save });
|
||||
|
||||
socials.forEach(social => {
|
||||
test(`should hide ${social.name} checkmark by default`, async ({
|
||||
page
|
||||
}) => {
|
||||
await expect(page.getByTestId(social.checkTestId)).toBeHidden();
|
||||
});
|
||||
await expect(saveButton).toBeVisible();
|
||||
await saveButton.click();
|
||||
await expect(page.getByRole('alert').first()).toContainText(
|
||||
'We have updated your social links'
|
||||
);
|
||||
|
||||
test(`should update ${social.name} URL`, async ({ page }) => {
|
||||
const socialInput = page.getByRole('textbox', { name: social.label });
|
||||
await expect(socialInput).toBeVisible();
|
||||
await socialInput.fill(social.url);
|
||||
const socialCheckmark = page.getByTestId(social.checkTestId);
|
||||
await expect(socialCheckmark).toBeVisible();
|
||||
|
||||
const saveButton = page
|
||||
.getByTestId(settingsPageElement.internetPresenceForm)
|
||||
.getByRole('button', { name: translations.buttons.save });
|
||||
|
||||
await expect(saveButton).toBeVisible();
|
||||
await saveButton.click();
|
||||
await expect(page.getByRole('alert').first()).toContainText(
|
||||
'We have updated your social links'
|
||||
);
|
||||
});
|
||||
await page.reload();
|
||||
await page.getByRole('button', { name: 'Edit my profile' }).click();
|
||||
await expect(page.getByRole('textbox', { name: 'GitHub' })).toHaveValue(
|
||||
githubUrl
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user