diff --git a/e2e/profile.spec.ts b/e2e/profile.spec.ts index d021006c4cf..902850a5dd6 100644 --- a/e2e/profile.spec.ts +++ b/e2e/profile.spec.ts @@ -81,106 +81,140 @@ const legacyCerts = [ { name: 'Legacy Full Stack', url: '/certification/certifieduser/full-stack' } ]; -test.use({ storageState: 'playwright/.auth/certified-user.json' }); - -test.beforeEach(async ({ page }) => { - await page.goto('/certifieduser'); - - // The following line is required if you're running the test in local development - // await page.getByRole('button', { name: 'Preview custom 404 page' }).click(); -}); - test.describe('Profile component', () => { - test('renders the camper profile correctly', async ({ page }) => { - // There are multiple avatars on the page, one is in the navbar, one is in the page body. - // The avatar we are interested in is the last one in the list - const avatar = page - .getByRole('img', { - name: translations.icons.avatar, - includeHidden: true // the svg has `aria-hidden` set to true - }) - .last(); + test.describe('when viewing my own profile', () => { + test.use({ storageState: 'playwright/.auth/certified-user.json' }); + test.beforeEach(async ({ page }) => { + await page.goto('/certifieduser'); - // "visible" as in the element is in the DOM, but it is hidden from non-sighted users - await expect(avatar).toBeVisible(); - - await expect( - page.getByRole('heading', { name: '@certifieduser' }) - ).toBeVisible(); - await expect(page.getByText('Full Stack User')).toBeVisible(); - await expect(page.getByText('Joined November 2020')).toBeVisible(); - await expect( - page.getByRole('link', { name: 'Top Contributor' }) - ).toBeVisible(); - await expect(page.getByText('2019')).toBeVisible(); - }); - - test('renders total points correctly', async ({ page }) => { - await expect(page.getByText('Total Points:')).toBeVisible(); - }); - - // The date range computation in this test doesn't match the implementation code, - // and causes the test to fail in some cases. - // We would want to mock system time to keep the test stable, - // but Playwright currently doesn't offer a built-in mechanism for this. - // Ref: https://github.com/microsoft/playwright/issues/6347 - test.skip('renders the heat map correctly', async ({ page }) => { - const today = new Date(); - const currentMonth = today.toLocaleString('en-US', { month: 'short' }); - const sixMonthsAgo = new Date(today.setMonth(today.getMonth() - 6)); - const sixMonthsAgoMonth = sixMonthsAgo.toLocaleString('en-US', { - month: 'short' + // The following line is required if you're running the test in local development + // await page + // .getByRole('button', { name: 'Preview custom 404 page' }) + // .click(); }); - const dateRange = `${sixMonthsAgoMonth} ${sixMonthsAgo.getFullYear()} - ${currentMonth} ${today.getFullYear()}`; - await expect(page.getByText(dateRange)).toBeVisible(); - await expect(page.locator('.react-calendar-heatmap')).toBeVisible(); - // Streak should be a non-negative integer - await expect(page.getByText(/Longest Streak: [0-9]\d*$/)).toBeVisible(); - await expect(page.getByText(/Current Streak: [0-9]\d*$/)).toBeVisible(); - }); - - test('displays certifications correctly', async ({ page }) => { - await expect( - page.getByRole('heading', { name: 'freeCodeCamp Certifications' }) - ).toBeVisible(); - await expect( - page.getByRole('heading', { name: 'Legacy Certifications' }) - ).toBeVisible(); - - for (const cert of certs) { - const link = page - .getByRole('link', { - name: `View ${cert.name} Certification` - }) - .first(); - await expect(link).toBeVisible(); - await expect(link).toHaveAttribute('href', cert.url); - } - - for (const cert of legacyCerts) { - const link = page - .getByRole('link', { - name: `View ${cert.name} Certification` + test('renders the camper profile correctly', async ({ page }) => { + // There are multiple avatars on the page, one is in the navbar, one is in the page body. + // The avatar we are interested in is the last one in the list + const avatar = page + .getByRole('img', { + name: translations.icons.avatar, + includeHidden: true // the svg has `aria-hidden` set to true }) .last(); - await expect(link).toBeVisible(); - await expect(link).toHaveAttribute('href', cert.url); - } + + // "visible" as in the element is in the DOM, but it is hidden from non-sighted users + await expect(avatar).toBeVisible(); + + await expect( + page.getByRole('heading', { name: '@certifieduser' }) + ).toBeVisible(); + await expect(page.getByText('Full Stack User')).toBeVisible(); + await expect(page.getByText('Joined November 2020')).toBeVisible(); + await expect( + page.getByRole('link', { name: 'Top Contributor' }) + ).toBeVisible(); + await expect(page.getByText('2019')).toBeVisible(); + }); + + test('renders total points correctly', async ({ page }) => { + await expect(page.getByText('Total Points:')).toBeVisible(); + }); + + // The date range computation in this test doesn't match the implementation code, + // and causes the test to fail in some cases. + // We would want to mock system time to keep the test stable, + // but Playwright currently doesn't offer a built-in mechanism for this. + // Ref: https://github.com/microsoft/playwright/issues/6347 + test.skip('renders the heat map correctly', async ({ page }) => { + const today = new Date(); + const currentMonth = today.toLocaleString('en-US', { month: 'short' }); + const sixMonthsAgo = new Date(today.setMonth(today.getMonth() - 6)); + const sixMonthsAgoMonth = sixMonthsAgo.toLocaleString('en-US', { + month: 'short' + }); + const dateRange = `${sixMonthsAgoMonth} ${sixMonthsAgo.getFullYear()} - ${currentMonth} ${today.getFullYear()}`; + + await expect(page.getByText(dateRange)).toBeVisible(); + await expect(page.locator('.react-calendar-heatmap')).toBeVisible(); + // Streak should be a non-negative integer + await expect(page.getByText(/Longest Streak: [0-9]\d*$/)).toBeVisible(); + await expect(page.getByText(/Current Streak: [0-9]\d*$/)).toBeVisible(); + }); + + test('displays certifications correctly', async ({ page }) => { + await expect( + page.getByRole('heading', { name: 'freeCodeCamp Certifications' }) + ).toBeVisible(); + await expect( + page.getByRole('heading', { name: 'Legacy Certifications' }) + ).toBeVisible(); + + for (const cert of certs) { + const link = page + .getByRole('link', { + name: `View ${cert.name} Certification` + }) + .first(); + await expect(link).toBeVisible(); + await expect(link).toHaveAttribute('href', cert.url); + } + + for (const cert of legacyCerts) { + const link = page + .getByRole('link', { + name: `View ${cert.name} Certification` + }) + .last(); + await expect(link).toBeVisible(); + await expect(link).toHaveAttribute('href', cert.url); + } + }); + + test('should not show portfolio when empty', async ({ page }) => { + // @certifieduser doesn't have portfolio information + await expect( + page.getByText(translations.profile.projects) + ).not.toBeVisible(); + }); + + test('displays the timeline correctly', async ({ page }) => { + await expect( + page.getByRole('heading', { name: 'Timeline' }) + ).toBeVisible(); + await expect(page.getByRole('table')).toBeVisible(); + await expect( + page.getByRole('navigation', { name: 'Timeline Pagination' }) + ).toBeVisible(); + }); }); - test('should not show portfolio when empty', async ({ page }) => { - // @certifieduser doesn't have portfolio information - await expect( - page.getByText(translations.profile.projects) - ).not.toBeVisible(); - }); + test.describe("when viewing someone else's profile", () => { + test.beforeEach(async ({ page }) => { + await page.goto('/publicUser'); - test('displays the timeline correctly', async ({ page }) => { - await expect(page.getByRole('heading', { name: 'Timeline' })).toBeVisible(); - await expect(page.getByRole('table')).toBeVisible(); - await expect( - page.getByRole('navigation', { name: 'Timeline Pagination' }) - ).toBeVisible(); + // The following line is required if you're running the test in local development + // await page + // .getByRole('button', { name: 'Preview custom 404 page' }) + // .click(); + }); + + test.describe('while logged in', () => { + test.use({ storageState: 'playwright/.auth/certified-user.json' }); + + test('displays the public username', async ({ page }) => { + await expect( + page.getByRole('heading', { name: '@publicuser' }) + ).toBeVisible(); + }); + }); + + test.describe('logged out', () => { + test('displays the public username', async ({ page }) => { + await expect( + page.getByRole('heading', { name: '@publicuser' }) + ).toBeVisible(); + }); + }); }); }); diff --git a/tools/scripts/seed/seed-demo-user.js b/tools/scripts/seed/seed-demo-user.js index a971d8dc7f2..7df0ceda43b 100644 --- a/tools/scripts/seed/seed-demo-user.js +++ b/tools/scripts/seed/seed-demo-user.js @@ -2,7 +2,12 @@ const path = require('path'); const debug = require('debug'); require('dotenv').config({ path: path.resolve(__dirname, '../../../.env') }); const { MongoClient, ObjectId } = require('mongodb'); -const { demoUser, blankUser, fullyCertifiedUser } = require('./user-data'); +const { + demoUser, + blankUser, + publicUser, + fullyCertifiedUser +} = require('./user-data'); const args = process.argv.slice(2); @@ -102,7 +107,8 @@ const user = db.collection('user'); const userIds = [ new ObjectId('5fa2db00a25c1c1fa49ce067'), new ObjectId('5bd30e0f1caf6ac3ddddddb5'), - new ObjectId('5bd30e0f1caf6ac3ddddddb9') + new ObjectId('5bd30e0f1caf6ac3ddddddb9'), + new ObjectId('663b839b24a8b29f57728b13') ]; const dropUserTokens = async function () { @@ -130,9 +136,11 @@ const run = async () => { if (args.includes('certified-user')) { await user.insertOne(fullyCertifiedUser); await user.insertOne(blankUser); + await user.insertOne(publicUser); } else { await user.insertOne(demoUser); await user.insertOne(blankUser); + await user.insertOne(publicUser); } log('local auth user seed complete'); }; diff --git a/tools/scripts/seed/user-data.js b/tools/scripts/seed/user-data.js index 413a31eb1eb..dd1ed60478a 100644 --- a/tools/scripts/seed/user-data.js +++ b/tools/scripts/seed/user-data.js @@ -63,6 +63,67 @@ module.exports = { externalId: '', unsubscribeId: 'ecJxUi7OM49f24hTpauP8' }, + publicUser: { + _id: new ObjectId('663b839b24a8b29f57728b13'), + email: 'bar@bars.com', + emailVerified: true, + progressTimestamps: [], + isBanned: false, + isCheater: false, + username: 'publicuser', + about: '', + name: 'Public User', + location: '', + picture: '', + acceptedPrivacyTerms: true, + sendQuincyEmail: false, + currentChallengeId: '', + isHonest: false, + isFrontEndCert: false, + isDataVisCert: false, + isBackEndCert: false, + isFullStackCert: false, + isRespWebDesignCert: false, + is2018DataVisCert: false, + isFrontEndLibsCert: false, + isJsAlgoDataStructCert: false, + isApisMicroservicesCert: false, + isInfosecQaCert: false, + isQaCertV7: false, + isInfosecCertV7: false, + is2018FullStackCert: false, + isSciCompPyCertV7: false, + isDataAnalysisPyCertV7: false, + isMachineLearningPyCertV7: false, + isRelationalDatabaseCertV8: false, + isCollegeAlgebraPyCertV8: false, + isFoundationalCSharpCertV8: false, + completedChallenges: [], + portfolio: [], + yearsTopContributor: [], + rand: 0.6126749173148205, + theme: 'default', + profileUI: { + isLocked: false, + showAbout: true, + showCerts: true, + showDonation: true, + showHeatMap: true, + showLocation: true, + showName: true, + showPoints: true, + showPortfolio: true, + showTimeLine: true + }, + badges: { + coreTeam: [] + }, + isDonating: false, + emailAuthLinkTTL: null, + emailVerifyTTL: null, + externalId: '', + unsubscribeId: 'ecJxUi7OM49f24hTpauP8' + }, demoUser: { _id: new ObjectId('5bd30e0f1caf6ac3ddddddb5'), email: 'foo@bar.com',