Skip to content
Merged
6 changes: 4 additions & 2 deletions playwright-tests/tests/becomeAMentee.page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { HomePage } from '@pages/home.page';
import { MentorshipPage } from '@pages/mentorship.page';

test('Validate "Become a Mentee" section and Find a Mentor button', async ({
page, mentorshipPage, homePage
page,
mentorshipPage,
homePage,
}) => {
// Navigate to Mentorship page
await page.goto('/mentorship');
Expand All @@ -22,7 +24,7 @@ test('Validate "Become a Mentee" section and Find a Mentor button', async ({
];

await expect(mentorshipPage.menteeListItems).toHaveText(items);

await homePage.findMentorButton.click();
await expect(page).toHaveURL(/\/mentorship\/mentors/);
});
116 changes: 114 additions & 2 deletions src/__tests__/pages/MenteeRegistrationPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ jest.mock('next/router', () => ({
useRouter: () => ({ push: jest.fn(), pathname: '/' }),
}));

// Mutable flag so individual tests can override the registration state
// Mutable flags so individual tests can override registration state
let mockIsRegistrationOpen = true;
let mockIsAdhocCycle = false;

// Mock the registration toggle
jest.mock('../../utils/mentorshipConstants', () => ({
...jest.requireActual('../../utils/mentorshipConstants'),
get IS_REGISTRATION_OPEN() {
return mockIsRegistrationOpen;
},
get IS_ADHOC_CYCLE() {
return mockIsAdhocCycle;
},
}));

const renderPage = () =>
Expand Down Expand Up @@ -185,3 +188,112 @@ describe('MenteeRegistrationPage - registration closed', () => {
expect(screen.queryByText('Step 1 of 3')).not.toBeInTheDocument();
});
});

describe('MenteeRegistrationPage - adhoc cycle', () => {
beforeEach(() => {
mockIsAdhocCycle = true;
globalThis.fetch = jest.fn().mockResolvedValue({
ok: true,
json: jest.fn().mockResolvedValue([]),
});
});

afterEach(() => {
mockIsAdhocCycle = false;
jest.resetAllMocks();
});

it('shows ad-hoc breadcrumb label', () => {
renderPage();
expect(screen.getByText('Ad-hoc Mentee Registration')).toBeInTheDocument();
});

it('does not render available hours per month field', () => {
renderPage();
expect(screen.queryByPlaceholderText('e.g. 4')).not.toBeInTheDocument();
});

it('navigates to step 2 after filling required fields', async () => {
renderPage();

fireEvent.change(screen.getByPlaceholderText('Jane Doe'), {
target: { value: 'Jane Doe' },
});
fireEvent.change(screen.getByPlaceholderText('jane@example.com'), {
target: { value: 'jane@example.com' },
});
fireEvent.change(screen.getByPlaceholderText('@jane'), {
target: { value: '@jane' },
});

const countrySelect = screen.getByRole('combobox');
fireEvent.mouseDown(countrySelect);
const countryOption = await screen.findByRole('option', {
name: /United Kingdom/i,
});
fireEvent.click(countryOption);

fireEvent.change(screen.getByPlaceholderText('London'), {
target: { value: 'London' },
});
fireEvent.change(
screen.getByPlaceholderText('e.g. Frontend Developer, Student'),
{ target: { value: 'Developer' } },
);
fireEvent.change(screen.getByPlaceholderText('Acme Corp'), {
target: { value: 'Tech Corp' },
});
fireEvent.change(
screen.getByPlaceholderText('https://www.linkedin.com/in/yourprofile'),
{ target: { value: 'https://www.linkedin.com/in/janedoe' } },
);

fireEvent.click(screen.getByRole('button', { name: /next/i }));

await waitFor(() => {
expect(screen.getByText('Step 2 of 3')).toBeInTheDocument();
});
});

it('shows mentorship goals field on step 2', async () => {
renderPage();

fireEvent.change(screen.getByPlaceholderText('Jane Doe'), {
target: { value: 'Jane Doe' },
});
fireEvent.change(screen.getByPlaceholderText('jane@example.com'), {
target: { value: 'jane@example.com' },
});
fireEvent.change(screen.getByPlaceholderText('@jane'), {
target: { value: '@jane' },
});

const countrySelect = screen.getByRole('combobox');
fireEvent.mouseDown(countrySelect);
const countryOption = await screen.findByRole('option', {
name: /United Kingdom/i,
});
fireEvent.click(countryOption);

fireEvent.change(screen.getByPlaceholderText('London'), {
target: { value: 'London' },
});
fireEvent.change(
screen.getByPlaceholderText('e.g. Frontend Developer, Student'),
{ target: { value: 'Developer' } },
);
fireEvent.change(screen.getByPlaceholderText('Acme Corp'), {
target: { value: 'Tech Corp' },
});
fireEvent.change(
screen.getByPlaceholderText('https://www.linkedin.com/in/yourprofile'),
{ target: { value: 'https://www.linkedin.com/in/janedoe' } },
);

fireEvent.click(screen.getByRole('button', { name: /next/i }));

await waitFor(() => {
expect(screen.getByText('Mentorship goals *')).toBeInTheDocument();
});
});
});
107 changes: 107 additions & 0 deletions src/__tests__/schemas/menteeSchema.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import {
adhocMenteeFormDefaultValues,
menteeFormSchema,
} from '../../schemas/menteeSchema';

const validLongTermBase = {
fullName: 'Jane Doe',
position: 'Developer',
email: 'jane@example.com',
slackDisplayName: '@jane',
companyName: 'Acme Corp',
country: { countryCode: 'GB', countryName: 'United Kingdom' },
city: 'London',
linkedInProfile: 'https://www.linkedin.com/in/janedoe',
pronouns: '',
availableHsMonth: 4,
skills: {
yearsExperience: 2,
areas: [{ technicalArea: 'FRONTEND', proficiencyLevel: 'INTERMEDIATE' }],
languages: [{ language: 'TYPESCRIPT', proficiencyLevel: 'INTERMEDIATE' }],
mentorshipFocus: ['GROW_BEGINNER_TO_MID'],
},
spokenLanguages: ['English'],
bio: 'A'.repeat(50),
mentorshipType: 'LONG_TERM' as const,
applications: [{ mentorId: 1, priorityOrder: 1, whyMentor: 'A'.repeat(50) }],
};

const validAdhocBase = {
...validLongTermBase,
mentorshipType: 'AD_HOC' as const,
availableHsMonth: 1,
};

describe('menteeFormSchema — long-term', () => {
it('accepts valid long-term data', () => {
const result = menteeFormSchema.safeParse(validLongTermBase);
expect(result.success).toBe(true);
});

it('rejects long-term data with no mentorshipFocus', () => {
const data = {
...validLongTermBase,
skills: { ...validLongTermBase.skills, mentorshipFocus: [] },
};
const result = menteeFormSchema.safeParse(data);
expect(result.success).toBe(false);
if (!result.success) {
const paths = result.error.issues.map((i) => i.path.join('.'));
expect(paths).toContain('skills.mentorshipFocus');
}
});
});

describe('menteeFormSchema — adhoc', () => {
it('accepts valid adhoc data', () => {
const result = menteeFormSchema.safeParse(validAdhocBase);
expect(result.success).toBe(true);
});

it('requires mentorshipFocus for adhoc', () => {
const data = {
...validAdhocBase,
skills: { ...validAdhocBase.skills, mentorshipFocus: [] },
};
const result = menteeFormSchema.safeParse(data);
expect(result.success).toBe(false);
if (!result.success) {
const paths = result.error.issues.map((i) => i.path.join('.'));
expect(paths).toContain('skills.mentorshipFocus');
}
});

it('accepts adhoc data with mentorshipFocus selected', () => {
const result = menteeFormSchema.safeParse(validAdhocBase);
expect(result.success).toBe(true);
});
});

describe('menteeFormSchema — availableHsMonth', () => {
it('rejects long-term data with availableHsMonth less than 2', () => {
const data = { ...validLongTermBase, availableHsMonth: 1 };
const result = menteeFormSchema.safeParse(data);
expect(result.success).toBe(false);
if (!result.success) {
const paths = result.error.issues.map((i) => i.path.join('.'));
expect(paths).toContain('availableHsMonth');
}
});

it('accepts long-term data with availableHsMonth of 2', () => {
const data = { ...validLongTermBase, availableHsMonth: 2 };
const result = menteeFormSchema.safeParse(data);
expect(result.success).toBe(true);
});

it('accepts adhoc data with availableHsMonth of 1', () => {
const result = menteeFormSchema.safeParse(validAdhocBase);
expect(result.success).toBe(true);
});
});

describe('adhocMenteeFormDefaultValues', () => {
it('sets mentorshipType to AD_HOC', () => {
expect(adhocMenteeFormDefaultValues.mentorshipType).toBe('AD_HOC');
});
});
Loading
Loading