feat: convert navbar test to Playwright (#55034)
Co-authored-by: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com>pull/55074/head
parent
eee82c690b
commit
05a962b6a9
|
@ -1,61 +0,0 @@
|
|||
const navBarselectors = {
|
||||
heading: "[data-test-label='landing-header']",
|
||||
smallCallToAction: "[data-test-label='landing-small-cta']",
|
||||
navigationLinks: '.nav-list',
|
||||
avatarContainer: '.avatar-container',
|
||||
defaultAvatar: '.avatar-container',
|
||||
menuButton: '#toggle-button-nav',
|
||||
avatarImage: '.avatar-container .avatar'
|
||||
};
|
||||
|
||||
describe('Navbar when logged out', () => {
|
||||
it('should have the sign in button on landing and /learn', () => {
|
||||
cy.visit('/');
|
||||
|
||||
cy.contains(navBarselectors.smallCallToAction, 'Sign in');
|
||||
|
||||
cy.visit('/learn');
|
||||
cy.contains(navBarselectors.smallCallToAction, 'Sign in');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Navbar Logged in', () => {
|
||||
beforeEach(() => {
|
||||
cy.login();
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
it('Should render properly', () => {
|
||||
cy.get('#universal-nav').should('be.visible');
|
||||
cy.get('#universal-nav').should('have.class', 'universal-nav');
|
||||
});
|
||||
|
||||
it(
|
||||
'Should take user to learn page when clicked on ' + 'the freeCodeCamp logo',
|
||||
() => {
|
||||
cy.get('#universal-nav-logo').within(() => {
|
||||
cy.get('svg').click();
|
||||
});
|
||||
cy.url().should('include', '/learn');
|
||||
}
|
||||
);
|
||||
|
||||
it('Should have `Profile` link when user is signed in', () => {
|
||||
cy.get(navBarselectors.menuButton).click();
|
||||
cy.get(navBarselectors.navigationLinks).contains('Profile').click();
|
||||
cy.url().should('include', '/developmentuser');
|
||||
});
|
||||
|
||||
it('Should have a profile image with class `default-border`', () => {
|
||||
cy.get(navBarselectors.avatarContainer).should(
|
||||
'have.class',
|
||||
'default-border'
|
||||
);
|
||||
cy.get(navBarselectors.defaultAvatar).should('exist');
|
||||
});
|
||||
|
||||
it('Should have a profile image with dimensions that are <= 26px', () => {
|
||||
cy.get(navBarselectors.avatarImage).invoke('width').should('lte', 26);
|
||||
cy.get(navBarselectors.avatarImage).invoke('height').should('lte', 26);
|
||||
});
|
||||
});
|
|
@ -1,3 +1,4 @@
|
|||
import { execSync } from 'child_process';
|
||||
import { test, expect } from '@playwright/test';
|
||||
import translations from '../client/i18n/locales/english/translations.json';
|
||||
import { availableLangs, hiddenLangs, LangNames } from '../shared/config/i18n';
|
||||
|
@ -20,19 +21,28 @@ const headerComponentElements = {
|
|||
const examUrl =
|
||||
'/learn/foundational-c-sharp-with-microsoft/foundational-c-sharp-with-microsoft-certification-exam/foundational-c-sharp-with-microsoft-certification-exam';
|
||||
|
||||
test.use({ storageState: 'playwright/.auth/certified-user.json' });
|
||||
test.describe('Header', () => {
|
||||
test.use({ storageState: 'playwright/.auth/development-user.json' });
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
});
|
||||
});
|
||||
|
||||
test('Has link for skip content', async ({ page }) => {
|
||||
test.beforeAll(() => {
|
||||
execSync('node ./tools/scripts/seed/seed-demo-user');
|
||||
});
|
||||
|
||||
test.afterAll(() => {
|
||||
execSync('node ./tools/scripts/seed/seed-demo-user certified-user');
|
||||
});
|
||||
|
||||
test('Has link for skip content', async ({ page }) => {
|
||||
const skipContent = page.getByTestId(headerComponentElements.skipContent);
|
||||
await expect(skipContent).toBeVisible();
|
||||
await expect(skipContent).toHaveAttribute('href', '#content-start');
|
||||
});
|
||||
});
|
||||
|
||||
test('Renders universal nav by default', async ({ page }) => {
|
||||
test('Renders universal nav by default', async ({ page }) => {
|
||||
const universalNavigation = page.getByTestId(
|
||||
headerComponentElements.universalNav
|
||||
);
|
||||
|
@ -42,12 +52,12 @@ test('Renders universal nav by default', async ({ page }) => {
|
|||
await expect(universalNavigation).toBeVisible();
|
||||
await expect(universalNavigationLogo).toBeVisible();
|
||||
await expect(universalNavigationLogo).toHaveAttribute('href', '/learn');
|
||||
});
|
||||
});
|
||||
|
||||
test('Should display search in header on desktop and in menu on mobile', async ({
|
||||
test('Should display search in header on desktop and in menu on mobile', async ({
|
||||
page,
|
||||
isMobile
|
||||
}) => {
|
||||
}) => {
|
||||
const searchInput = page.getByLabel(translations.search.label);
|
||||
const menuButton = page.getByTestId(headerComponentElements.menuButton);
|
||||
|
||||
|
@ -58,11 +68,11 @@ test('Should display search in header on desktop and in menu on mobile', async (
|
|||
} else {
|
||||
await expect(searchInput).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('Clicking the "Change Language" button should open the language list', async ({
|
||||
test('Clicking the "Change Language" button should open the language list', async ({
|
||||
page
|
||||
}) => {
|
||||
}) => {
|
||||
const toggleLangButton = page.getByTestId(
|
||||
headerComponentElements.toggleLangButton
|
||||
);
|
||||
|
@ -70,11 +80,11 @@ test('Clicking the "Change Language" button should open the language list', asyn
|
|||
await toggleLangButton.click();
|
||||
const langList = page.getByTestId(headerComponentElements.languageList);
|
||||
await expect(langList).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test('The language list should contain a button for each available language', async ({
|
||||
test('The language list should contain a button for each available language', async ({
|
||||
page
|
||||
}) => {
|
||||
}) => {
|
||||
const locales = availableLangs.client.filter(
|
||||
lang => !hiddenLangs.includes(lang)
|
||||
);
|
||||
|
@ -87,26 +97,28 @@ test('The language list should contain a button for each available language', as
|
|||
const langList = page.getByTestId(headerComponentElements.languageList);
|
||||
await expect(langList).toBeVisible();
|
||||
|
||||
const langButtons = page.getByTestId(headerComponentElements.languageButton);
|
||||
const langButtons = page.getByTestId(
|
||||
headerComponentElements.languageButton
|
||||
);
|
||||
await expect(langButtons).toHaveCount(locales.length);
|
||||
|
||||
for (let i = 0; i < locales.length; i++) {
|
||||
const btn = langButtons.nth(i);
|
||||
await expect(btn).toContainText(LangNames[locales[i]]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('Clicking the menu button should open the menu', async ({ page }) => {
|
||||
test('Clicking the menu button should open the menu', async ({ page }) => {
|
||||
const menuButton = page.getByTestId(headerComponentElements.menuButton);
|
||||
const menu = page.getByTestId(headerComponentElements.menu);
|
||||
await expect(menuButton).toBeVisible();
|
||||
await menuButton.click();
|
||||
await expect(menu).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test('Focusing on a menu item, and pressing Esc should close the menu and focus on the menu button', async ({
|
||||
test('Focusing on a menu item, and pressing Esc should close the menu and focus on the menu button', async ({
|
||||
page
|
||||
}) => {
|
||||
}) => {
|
||||
const menuButton = page.getByTestId(headerComponentElements.menuButton);
|
||||
const menu = page.getByTestId(headerComponentElements.menu);
|
||||
|
||||
|
@ -120,11 +132,11 @@ test('Focusing on a menu item, and pressing Esc should close the menu and focus
|
|||
await expect(menu).toBeHidden();
|
||||
|
||||
await expect(menuButton).toBeFocused();
|
||||
});
|
||||
});
|
||||
|
||||
test('The menu should contain links to: donate, curriculum, forum, news, radio, contribute, and podcast', async ({
|
||||
test('The menu should contain links to: donate, curriculum, forum, news, radio, contribute, and podcast', async ({
|
||||
page
|
||||
}) => {
|
||||
}) => {
|
||||
const menuButton = page.getByTestId(headerComponentElements.menuButton);
|
||||
const menu = page.getByTestId(headerComponentElements.menu);
|
||||
await expect(menuButton).toBeVisible();
|
||||
|
@ -132,6 +144,7 @@ test('The menu should contain links to: donate, curriculum, forum, news, radio,
|
|||
await expect(menu).toBeVisible();
|
||||
|
||||
const menuLinks = [
|
||||
{ name: translations.buttons.profile, href: '/developmentuser' },
|
||||
{
|
||||
name: translations.buttons.donate,
|
||||
href: '/donate'
|
||||
|
@ -167,9 +180,9 @@ test('The menu should contain links to: donate, curriculum, forum, news, radio,
|
|||
await expect(link).toBeVisible();
|
||||
await expect(link).toHaveAttribute('href', menuLink.href);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('The menu should be able to change the theme', async ({ page }) => {
|
||||
test('The menu should be able to change the theme', async ({ page }) => {
|
||||
const menuButton = page.getByTestId(headerComponentElements.menuButton);
|
||||
const menu = page.getByTestId(headerComponentElements.menu);
|
||||
await menuButton.click();
|
||||
|
@ -192,36 +205,37 @@ test('The menu should be able to change the theme', async ({ page }) => {
|
|||
|
||||
await themeButton.click();
|
||||
await expect(page.locator('body')).toHaveClass('light-palette');
|
||||
});
|
||||
});
|
||||
|
||||
test('The header should contain an avatar', async ({ page }) => {
|
||||
const avatarLink = page.locator('.avatar-nav-link');
|
||||
test('The header should contain an avatar', async ({ page }) => {
|
||||
const avatarLink = page.getByRole('link', { name: 'Profile' });
|
||||
await expect(avatarLink).toBeVisible();
|
||||
await expect(avatarLink).toHaveAttribute('href', '/certifieduser');
|
||||
await expect(avatarLink).toHaveAttribute('href', '/developmentuser');
|
||||
|
||||
const avatarContainer = page.locator('.avatar-container');
|
||||
await expect(avatarContainer).toHaveClass('avatar-container blue-border');
|
||||
});
|
||||
const avatar = avatarLink.getByRole('img', {
|
||||
name: 'Default Avatar',
|
||||
includeHidden: true // the svg is aria-hidden
|
||||
});
|
||||
await expect(avatar).toBeVisible();
|
||||
});
|
||||
|
||||
test('Renders exam nav for Foundational C# with Microsoft exam', async ({
|
||||
page
|
||||
}) => {
|
||||
await page.goto(examUrl);
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: translations.buttons['click-start-exam']
|
||||
})
|
||||
.click();
|
||||
await expect(page).toHaveURL(examUrl);
|
||||
await expect(page.getByTestId(headerComponentElements.examNav)).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId(headerComponentElements.examNavLogo)
|
||||
).toBeVisible();
|
||||
});
|
||||
test('The Avatar should be less or equal to 26px', async ({ page }) => {
|
||||
const avatar = page
|
||||
.getByRole('link', { name: 'Profile' })
|
||||
.getByRole('img', {
|
||||
name: 'Default Avatar',
|
||||
includeHidden: true // the svg is aria-hidden
|
||||
});
|
||||
|
||||
test('The Sign In button should redirect to api/signin', async ({
|
||||
await expect(avatar).toBeVisible();
|
||||
const avatarSize = await avatar.boundingBox();
|
||||
expect(avatarSize?.width).toBeLessThanOrEqual(26);
|
||||
expect(avatarSize?.height).toBeLessThanOrEqual(26);
|
||||
});
|
||||
|
||||
test('The Sign In button should redirect to api/signin', async ({
|
||||
browser
|
||||
}) => {
|
||||
}) => {
|
||||
// Sign out user in order to test Sign In button
|
||||
const context = await browser.newContext({
|
||||
storageState: { cookies: [], origins: [] }
|
||||
|
@ -236,11 +250,11 @@ test('The Sign In button should redirect to api/signin', async ({
|
|||
const apiLocation = process.env.API_LOCATION || 'http://localhost:3000';
|
||||
|
||||
await expect(signInButton).toHaveAttribute('href', `${apiLocation}/signin`);
|
||||
});
|
||||
});
|
||||
|
||||
test('When the user is signed out, only certain elements should be visible', async ({
|
||||
test('When the user is signed out, only certain elements should be visible', async ({
|
||||
browser
|
||||
}) => {
|
||||
}) => {
|
||||
const context = await browser.newContext({
|
||||
storageState: { cookies: [], origins: [] }
|
||||
});
|
||||
|
@ -250,6 +264,35 @@ test('When the user is signed out, only certain elements should be visible', asy
|
|||
.getByTestId(headerComponentElements.signInButton)
|
||||
.nth(0);
|
||||
await expect(signInButton).toBeVisible();
|
||||
await expect(page.locator('.avatar-nav-link')).toBeHidden();
|
||||
await expect(page.locator('.avatar-container')).toBeHidden();
|
||||
|
||||
const avatar = page
|
||||
.getByRole('link', { name: 'Profile' })
|
||||
.getByRole('img', {
|
||||
name: 'Default Avatar',
|
||||
includeHidden: true // the svg is aria-hidden
|
||||
});
|
||||
await expect(avatar).toBeHidden();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Exam Header', () => {
|
||||
test.use({ storageState: 'playwright/.auth/certified-user.json' });
|
||||
|
||||
test('Renders exam nav for Foundational C# with Microsoft exam', async ({
|
||||
page
|
||||
}) => {
|
||||
await page.goto(examUrl);
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: translations.buttons['click-start-exam']
|
||||
})
|
||||
.click();
|
||||
await expect(page).toHaveURL(examUrl);
|
||||
await expect(
|
||||
page.getByTestId(headerComponentElements.examNav)
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByTestId(headerComponentElements.examNavLogo)
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue