fix(tools): seed ms account when seeding certified user (#52967)
parent
a7e4553d4a
commit
bbf551b93c
|
@ -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' />
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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));
|
Loading…
Reference in New Issue