fix(tools): seed ms account when seeding certified user (#52967)

pull/53059/head
Huyen Nguyen 2024-01-09 04:59:48 +07:00 committed by GitHub
parent a7e4553d4a
commit bbf551b93c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 179 additions and 64 deletions

View File

@ -90,9 +90,7 @@ function LinkMsUser({
<ChallengeHeading heading={t('learn.ms.link-header')} />
<Spacer size='small' />
<p data-playwright-test-label='link-signin-text'>
{t('learn.ms.link-signin')}
</p>
<p>{t('learn.ms.link-signin')}</p>
<Login />
</>
) : (
@ -114,11 +112,9 @@ function LinkMsUser({
<ChallengeHeading heading={'learn.ms.link-header'} />
<Spacer size='small' />
<p data-playwright-test-label='unlinked-text'>
{t('learn.ms.unlinked')}
</p>
<p>{t('learn.ms.unlinked')}</p>
<ol className='link-ms-user-ol'>
<li data-playwright-test-label='link-li-1-text'>
<li>
<Trans i18nKey='learn.ms.link-li-1'>
<a
href='https://learn.microsoft.com/users/me/transcript'
@ -129,23 +125,15 @@ function LinkMsUser({
</a>
</Trans>
</li>
<li data-playwright-test-label='link-li-2-text'>
{t('learn.ms.link-li-2')}
</li>
<li data-playwright-test-label='link-li-3-text'>
{t('learn.ms.link-li-3')}
</li>
<li data-playwright-test-label='link-li-4-text'>
{t('learn.ms.link-li-4')}
</li>
<li data-playwright-test-label='link-li-5-text'>
<li>{t('learn.ms.link-li-2')}</li>
<li>{t('learn.ms.link-li-3')}</li>
<li>{t('learn.ms.link-li-4')}</li>
<li>
<Trans i18nKey='learn.ms.link-li-5'>
<pre className='language-html'>placeholder</pre>
</Trans>
</li>
<li data-playwright-test-label='link-li-6-text'>
{t('learn.ms.link-li-6')}
</li>
<li>{t('learn.ms.link-li-6')}</li>
</ol>
<Spacer size='medium' />

View File

@ -7,63 +7,115 @@ test.beforeEach(async ({ page }) => {
);
});
test.describe('Link MS user component (unlinked signedOut user)', () => {
test('Component has proper main heading and relevant sections', async ({
test.describe('Link MS user component (signed-out user)', () => {
test('should display the page content with a signin CTA', async ({
page
}) => {
const mainHeading = page.getByRole('heading', {
name: translations.learn.ms['link-header']
});
await expect(mainHeading).toBeVisible();
await expect(
page.getByRole('heading', {
name: 'Trophy - Write Your First Code Using C#',
level: 1
})
).toBeVisible();
const linkSignInText = page.getByTestId('link-signin-text');
await expect(linkSignInText).toBeVisible();
await expect(
page.getByRole('heading', {
name: translations.learn.ms['link-header'],
level: 2
})
).toBeVisible();
await expect(
page.getByText(translations.learn.ms['link-signin'])
).toBeVisible();
// There are 2 sign in button on the page: one in the navbar, and one in the page content
const signInButtons = await page
.getByRole('link', { name: translations.buttons['sign-in'] })
.all();
expect(signInButtons).toHaveLength(2);
});
});
test.describe('Link MS user component (unlinked signedIn user)', () => {
test.describe('Link MS user component (signed-in user)', () => {
test.use({ storageState: 'playwright/.auth/certified-user.json' });
test('Component has proper main heading and relevant sections', async ({
page
}) => {
const mainHeading = page.getByRole('heading', {
name: translations.learn.ms['link-header']
});
await expect(mainHeading).toBeVisible();
test("should recognize the user's MS account", async ({ page }) => {
await expect(
page.getByRole('heading', {
name: 'Trophy - Write Your First Code Using C#',
level: 1
})
).toBeVisible();
const linkSignInText = page.getByTestId('unlinked-text');
await expect(linkSignInText).toBeVisible();
await expect(
page.getByText(
'The Microsoft account with username "certifieduser" is currently linked to your freeCodeCamp account. If this is not your Microsoft username, remove the link.'
)
).toBeVisible();
});
test('Component has proper list of actions', async ({ page }) => {
const linkText1 = page.getByTestId('link-li-1-text');
await expect(linkText1).toBeVisible();
await expect(linkText1).toContainText(
'Using a browser where you are logged into your Microsoft account, go to https://learn.microsoft.com/users/me/transcript'
);
test('should allow the user to unlink their MS account and display a form for re-link', async ({
page
}) => {
// Intercept the endpoint to prevent `msUsername` from being deleted
// as the deletion will cause subsequent tests to fail
await page.route('*/**/user/ms-username', async route => {
const json = { msUsername: null };
await route.fulfill({ json });
});
const linkText2 = page.getByTestId('link-li-2-text');
await expect(linkText2).toBeVisible();
await expect(linkText2).toHaveText(translations.learn.ms['link-li-2']);
const unlinkButton = page.getByRole('button', {
name: translations.buttons['unlink-account']
});
await expect(unlinkButton).toBeVisible();
await unlinkButton.click();
const linkText3 = page.getByTestId('link-li-3-text');
await expect(linkText3).toBeVisible();
await expect(linkText3).toHaveText(translations.learn.ms['link-li-3']);
await expect(
page
.getByRole('alert')
.filter({ hasText: translations.flash.ms.transcript.unlinked })
).toBeVisible();
const linkText4 = page.getByTestId('link-li-4-text');
await expect(linkText4).toBeVisible();
await expect(linkText4).toHaveText(translations.learn.ms['link-li-4']);
const linkText5 = page.getByTestId('link-li-5-text');
await expect(linkText5).toBeVisible();
await expect(linkText5).toHaveText(
'Paste the URL into the input below, it should look similar to this: https://learn.microsoft.com/LOCALE/users/USERNAME/transcript/ID'
);
const linkText6 = page.getByTestId('link-li-6-text');
await expect(linkText6).toBeVisible();
await expect(linkText6).toHaveText(translations.learn.ms['link-li-6']);
await expect(
page.getByRole('heading', {
name: translations.learn.ms['link-header'],
level: 2
})
).toBeVisible();
await expect(page.getByText(translations.learn.ms.unlinked)).toBeVisible();
await expect(
page.getByRole('listitem').filter({
hasText:
'Using a browser where you are logged into your Microsoft account, go to https://learn.microsoft.com/users/me/transcript'
})
).toBeVisible();
await expect(
page
.getByRole('listitem')
.filter({ hasText: translations.learn.ms['link-li-2'] })
).toBeVisible();
await expect(
page
.getByRole('listitem')
.filter({ hasText: translations.learn.ms['link-li-3'] })
).toBeVisible();
await expect(
page
.getByRole('listitem')
.filter({ hasText: translations.learn.ms['link-li-4'] })
).toBeVisible();
await expect(
page.getByRole('listitem').filter({
hasText:
'Paste the URL into the input below, it should look similar to this: https://learn.microsoft.com/LOCALE/users/USERNAME/transcript/ID'
})
).toBeVisible();
await expect(
page
.getByRole('listitem')
.filter({ hasText: translations.learn.ms['link-li-6'] })
).toBeVisible();
const transcriptLinkInput = page.getByLabel(
translations.learn.ms['transcript-label']

View File

@ -72,9 +72,10 @@
"playwright:install-build-tools-linux": "sh ./playwright-install.sh",
"rename-challenges": "ts-node tools/challenge-helper-scripts/rename-challenge-files.ts",
"seed": "pnpm seed:surveys && pnpm seed:exams && cross-env DEBUG=fcc:* node ./tools/scripts/seed/seed-demo-user",
"seed:certified-user": "pnpm seed:surveys && pnpm seed:exams && cross-env DEBUG=fcc:* node ./tools/scripts/seed/seed-demo-user certified-user",
"seed:certified-user": "pnpm seed:surveys && pnpm seed:exams && pnpm seed:ms-username && cross-env DEBUG=fcc:* node ./tools/scripts/seed/seed-demo-user certified-user",
"seed:exams": "cross-env DEBUG=fcc:* node tools/scripts/seed-exams/create-exams",
"seed:surveys": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seed-surveys",
"seed:ms-username": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seed-ms-username",
"serve:client": "cd ./client && pnpm run serve",
"serve:client-ci": "cd ./client && pnpm run serve-ci",
"start": "npm-run-all create:shared -p develop:server serve:client",

View File

@ -0,0 +1,74 @@
const path = require('path');
const debug = require('debug');
const { MongoClient, ObjectId } = require('mongodb');
require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') });
const log = debug('fcc:tools:seedMsUsername');
const { MONGOHQ_URL } = process.env;
const args = process.argv.slice(2);
const allowedArgs = ['--delete-only'];
// Check for invalid arguments
args.forEach(arg => {
if (!allowedArgs.includes(arg))
throw new Error(
`Invalid argument ${arg}. Allowed arguments are ${allowedArgs.join(', ')}`
);
});
function handleError(err, client) {
if (err) {
console.error('Oh noes!! Error seeding MS username.');
console.error(err);
try {
client.close();
} catch (e) {
// no-op
} finally {
/* eslint-disable-next-line no-process-exit */
process.exit(1);
}
}
}
const msAccountId = new ObjectId('65785b25d4c5bd0565c0184d');
const certifiedUserAccount = {
_id: msAccountId,
userId: new ObjectId('5fa2db00a25c1c1fa49ce067'),
ttl: 77760000000,
msUsername: 'certifieduser'
};
const client = new MongoClient(MONGOHQ_URL, { useNewUrlParser: true });
log('Connected successfully to mongo');
const db = client.db('freecodecamp');
const msUsername = db.collection('MsUsername');
const run = async () => {
if (args.includes('--delete-only')) {
await msUsername.deleteOne({
_id: { $eq: msAccountId }
});
log('MS username deleted');
return;
}
// Rewrite if the object exists, create new if it doesn't
await msUsername.updateOne(
{ _id: msAccountId },
{ $set: certifiedUserAccount },
{ upsert: true }
);
log('MS username seeded');
};
run()
.then(() => client.close())
.catch(err => handleError(err, client));