JavaScript · Cypress
Recruitment with Cypress
Candidates filter jobs and apply through a 4-step form (contact, résumé upload, screening questions, review); recruiters sign in to shortlist, reject with a reason, view résumés and schedule interviews that update the candidate's status.
App under test
💼 HireHub
- URL
- /apps/jobs
- Recruiter
- recruiter@hirehub.dev
- Password
- Hire@123
- Résumé
- PDF/DOCX ≤ 2 MB
Scenarios to automate
Work top to bottom — each one adds a new technique.
- 1
Combined filters
Beginnerjob-search, job-location, job-experience, job-salary and remote-only narrow job-count.
- 2
Optional URL validation
Intermediateapplicant-linkedin can be blank, but a non-linkedin.com/in URL shows error-applicant-linkedin.
- 3
Upload rules
Intermediateresume-file rejects .txt/.jpg and >2 MB; the next step is blocked until a valid file is chosen.
- 4
Screening answers
Beginnerq-experience, q-authorized-yes/no and q-notice are all required; review-* shows them.
- 5
Two-role workflow
AdvancedApply as candidate → recruiter shortlists and schedules → application-status shows “Interview scheduled”.
- 6
Conditional actions
IntermediateOnly Applied rows show shortlist-*, only Shortlisted rows show schedule-*; Rejected rows show neither.
- 7
Modal validation
Intermediateconfirm-interview without day/time/mode shows schedule-error; weekends are disabled.
- 8
Save jobs
Beginnersave-job-<id> toggles aria-pressed (bookmark icon).
Sample Cypress suite
A working starting point that finds elements every way Cypress can — by role, label, text, id, name, CSS, XPath and data-testid — so you practice them all. Pick your language, switch to data-testid only to compare, or try your own in the Locator Playground.
Cypress runs inside the browser, so it only supports JavaScript and TypeScript — there is no Python, Java or C# version of Cypress. For those languages, see Selenium or Playwright.
// Uses the getByTestId custom command from the Cypress setup (cypress/support/commands.js).
// Locators in this suite: cy.contains ×6 · #id ×5 · [name] ×5 · [aria-label] ×1 · getByTestId ×15
describe('HireHub — recruitment', () => {
it('applies for a job and gets an interview', () => {
cy.visit('/apps/jobs');
cy.get('#job-search').type('QA');
cy.get('[aria-label="Remote only"]').click();
cy.getByTestId('job-count').should('contain', '2 jobs');
cy.getByTestId('view-job-j1').click();
cy.getByTestId('easy-apply').click();
cy.get('[name="applicant-name"]').type('Amir Khan');
cy.get('#applicant-email').type('amir@example.com');
cy.get('[name="applicant-phone"]').type('9876543210');
cy.getByTestId('apply-next').click();
cy.get('#resume-file').selectFile('cypress/fixtures/resume.pdf');
cy.getByTestId('apply-next').click();
cy.get('[name="q-experience"]').type('6');
cy.contains('button', 'Yes').click();
cy.get('#q-notice').select('30');
cy.getByTestId('apply-next').click();
cy.getByTestId('review-resume').should('contain', 'resume.pdf');
cy.contains('button', 'Submit application').click();
cy.getByTestId('application-id').should('contain', 'APP-501');
// Recruiter side
cy.contains('a', 'Recruiter').click();
cy.get('[name="recruiter-email"]').type('recruiter@hirehub.dev');
cy.get('#recruiter-password').type('Hire@123');
cy.contains('button', 'Sign in').click();
cy.getByTestId('job-applicants-j1').click();
cy.getByTestId('shortlist-APP-501').click();
cy.getByTestId('schedule-APP-501').click();
cy.get('[data-testid="interview-day"]:not([disabled])').first().click();
cy.get('[name="interview-time"]').select('11:30');
cy.getByTestId('interview-video').click();
cy.contains('button', 'Send invite').click();
cy.getByTestId('status-APP-501').should('contain', 'Interview scheduled');
cy.contains('a', 'My applications').click();
cy.getByTestId('application-status').should('contain', 'Interview scheduled');
cy.getByTestId('interview-details').should('be.visible');
});
});