diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000..2287dea --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,37 @@ +name: Playwright Tests +on: + push: + branches: [ '**' ] + pull_request: + # Runs on PRs to any branch + repository_dispatch: + types: [frontend-pr-update] + workflow_dispatch: + inputs: + frontend_branch: + description: 'Frontend branch to test against (if applicable)' + required: false + default: 'main' +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + ref: ${{ github.event.inputs.frontend_branch || github.ref }} + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/pages/AvuaEmployerPage.ts b/pages/AvuaEmployerPage.ts index 48d5b0f..ae858ce 100644 --- a/pages/AvuaEmployerPage.ts +++ b/pages/AvuaEmployerPage.ts @@ -9,6 +9,7 @@ export class AvuaEmployerPage { readonly publishButton: Locator; currentJobTitle: string = ""; + constructor(page: Page) { this.page = page; this.postJobButton = page.getByRole('button', { name: /Post a Job/i }).first(); @@ -84,8 +85,7 @@ export class AvuaEmployerPage { await cityInput.fill('New York City'); // Global applications - const globalBtn = this.page.getByRole('button', { name: /Yes, allow global applicants/i }).first(); - await globalBtn.click(); + // (This option seems to have been removed from the UI) } async injectReactStateOverrides(amount = 100, contractLength = "6", jobTitle?: string): Promise { diff --git a/tests/employerJobPost.spec.ts b/tests/employerJobPost.spec.ts index 6947d0d..6a63f75 100644 --- a/tests/employerJobPost.spec.ts +++ b/tests/employerJobPost.spec.ts @@ -13,7 +13,7 @@ test.describe('Employer Job Posting Flow', () => { test('should successfully post a contract job as an employer', async ({ page }) => { const employerPage = new AvuaEmployerPage(page); - const email = 'aakarshit.sharma+0@avua.com'; + const email = 'pranjil+test@avua.com'; const password = 'Test@123'; const jobTitle = `Playwright Test Engineer ${Date.now()}`; console.log('--- STARTING TEST ---'); diff --git a/tests/employerLogin.spec.ts b/tests/employerLogin.spec.ts new file mode 100644 index 0000000..55045ed --- /dev/null +++ b/tests/employerLogin.spec.ts @@ -0,0 +1,94 @@ +import { test, expect } from '@playwright/test'; +import { AvuaEmployerPage } from '../pages/AvuaEmployerPage'; + +const EMAIL = 'pranjil+test@avua.com'; +const PASS = 'Test@123'; + +test('TC1 - Valid login redirects to dashboard', async ({ page }) => { + const employer = new AvuaEmployerPage(page); + await employer.login(EMAIL, PASS); + await expect(page).toHaveURL(/\/employer\/dashboard/i); +}); + +test('TC3 - Sign-in is not clickable when email and password are empty', async ({ page }) => { + await page.goto('/employer-login'); + + // Switch to Password tab + const passwordTab = page.getByRole('button', { name: 'Password' }).first(); + await passwordTab.click(); + + // Try to click Sign in while fields are empty + const signInButton = page.getByRole('button', { name: 'Sign in' }); + await expect(signInButton).toBeDisabled(); +}); + +test('TC4 - Success message is shown and OTP is requested when valid email is submitted', async ({ page }) => { + await page.goto('/employer-login'); + + // Click One-time code tab + const otpTab = page.getByRole('button', { name: 'One-time code' }).first(); + await otpTab.click(); + + // Enter valid work email in "you@company.com" field + const emailInput = page.getByPlaceholder('you@company.com'); + await emailInput.fill('pranjil+test@avua.com'); + + // Click Send sign-in code button + const sendCodeBtn = page.getByRole('button', { name: 'Send sign-in code' }); + await sendCodeBtn.click(); + + // Verify success message is shown + await expect(page.getByText('One-time code sent successfully!')).toBeVisible(); + await expect(page.getByText(/We've sent an one-time code to your email/i)).toBeVisible(); +}); + +test('TC5 - Displays user doesnt exist when unregistered email is entered', async ({ page }) => { + await page.goto('/employer-login'); + + // Click One-time code tab + const otpTab = page.getByRole('button', { name: 'One-time code' }).first(); + await otpTab.click(); + + // Enter invalid/unregistered email (must have valid format to click button) + const emailInput = page.getByPlaceholder('you@company.com'); + await emailInput.fill('user@company.com'); + + // Click Send sign-in code button + const sendCodeBtn = page.getByRole('button', { name: 'Send sign-in code' }); + await sendCodeBtn.click(); + + // Displays user doesn't exist + await expect(page.getByText(/user does not exist/i)).toBeVisible(); +}); + +test('TC6 - Send sign-in code button is disabled when email field is empty', async ({ page }) => { + await page.goto('/employer-login'); + + // Click One-time code tab + const otpTab = page.getByRole('button', { name: 'One-time code' }).first(); + await otpTab.click(); + + // Leave "you@company.com" field empty + const emailInput = page.getByPlaceholder('you@company.com'); + await expect(emailInput).toBeEmpty(); + + // Verify Send sign-in code button is disabled + const sendCodeBtn = page.getByRole('button', { name: 'Send sign-in code' }); + await expect(sendCodeBtn).toBeDisabled(); +}); + +test('TC7 - Employer is redirected to forgot password page when clicking Forgot password link', async ({ page }) => { + await page.goto('/employer-login'); + + // Click Password tab + const passwordTab = page.getByRole('button', { name: 'Password' }).first(); + await passwordTab.click(); + + // Click "Forgot password?" link (it is rendered as text/button, not an link) + const forgotPasswordBtn = page.getByText('Forgot password?'); + await forgotPasswordBtn.click(); + + // Employer is redirected to forgot password page (rendered within same URL path) + await expect(page.getByText('Reset password in two quick steps')).toBeVisible(); + await expect(page.getByRole('button', { name: 'Reset password' })).toBeVisible(); +}); \ No newline at end of file