Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ORANGEHRM_BASE_URL=https://opensource-demo.orangehrmlive.com
ORANGEHRM_USERNAME=
ORANGEHRM_PASSWORD=
HEADLESS=true
BROWSER_CHANNEL=chrome
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules/
dist/
.env
reports/
playwright-report/
test-results/
artifacts/*.json
!artifacts/.gitkeep

31 changes: 31 additions & 0 deletions SPECS/orangehrm-hr-manager-directory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Feature Spec: OrangeHRM HR Manager Directory Search

## Goal
- Provide a local, maintainable automation project that logs into the OrangeHRM demo portal, filters the employee directory by the HR Manager job title, and captures the matching employees in a reusable report.

## Scope
- In:
- Playwright-based browser automation against the hosted OrangeHRM demo site.
- BDD scenarios implemented with Cucumber.
- Page Object Model structure for login, dashboard, and directory workflows.
- Local report generation that prints and persists the HR Manager list.
- A small frontend viewer that displays the generated HR Manager report locally.
- Out:
- Changes to the hosted OrangeHRM application.
- Backend services or data persistence outside generated local artifacts.
- Hardcoded credentials in source control.

## Requirements
- Credentials must be supplied through local environment variables.
- The automation must open the OrangeHRM login page, authenticate, navigate to Directory, and filter by the HR Manager job title.
- The framework must extract the matching employee names and associated directory metadata from the filtered search response.
- The extracted list must be printed during execution and saved to a local artifact file.
- The repository must include local run instructions for the BDD tests and the local report viewer.

## Acceptance Criteria
- [x] A BDD feature file covers successful authentication and HR Manager directory filtering.
- [x] Playwright page objects encapsulate login, dashboard navigation, and directory interactions.
- [x] Running the BDD suite locally can generate an `artifacts/hr-managers.json` report.
- [x] The report artifact contains the searched job title, generated timestamp, total results, and employee entries.
- [x] A local frontend viewer can render the generated report artifact when served locally.
- [x] Documentation explains environment setup, test execution, and report viewing.
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,3 @@
-

## New Feature Proposals
-
65 changes: 65 additions & 0 deletions app/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const statusMessage = document.getElementById('statusMessage');
const employeeList = document.getElementById('employeeList');
const totalResults = document.getElementById('totalResults');
const jobTitleChip = document.getElementById('jobTitleChip');
const generatedAt = document.getElementById('generatedAt');
const reloadButton = document.getElementById('reloadButton');

function setStatus(message) {
statusMessage.textContent = message;
}

function renderEmployees(employees) {
employeeList.innerHTML = '';

if (!employees.length) {
employeeList.innerHTML = '<p class="status-message">No HR Manager entries found in the current artifact.</p>';
return;
}

employees.forEach((employee, index) => {
const card = document.createElement('article');
card.className = 'employee-card';
card.style.animationDelay = `${index * 60}ms`;
card.innerHTML = `
<h3>${employee.name}</h3>
<p><strong>Job Title:</strong> ${employee.jobTitle}</p>
<p><strong>Sub Unit:</strong> ${employee.subUnit}</p>
<p><strong>Location:</strong> ${employee.location}</p>
`;
employeeList.appendChild(card);
});
}

async function loadReport() {
setStatus('Loading artifact...');

try {
const response = await fetch('/artifacts/hr-managers.json', { cache: 'no-store' });

if (!response.ok) {
throw new Error('Report artifact not found. Run the BDD suite to generate artifacts/hr-managers.json.');
}

const report = await response.json();
totalResults.textContent = String(report.totalResults ?? 0);
jobTitleChip.textContent = report.searchedJobTitle || 'Unknown job title';
generatedAt.textContent = report.generatedAt
? new Date(report.generatedAt).toLocaleString()
: 'Unknown timestamp';
renderEmployees(report.employees || []);
setStatus(`Loaded ${report.totalResults ?? 0} result(s).`);
} catch (error) {
totalResults.textContent = '0';
jobTitleChip.textContent = 'No artifact loaded';
generatedAt.textContent = 'Run the tests to generate data';
employeeList.innerHTML = '';
setStatus(error.message);
}
}

reloadButton.addEventListener('click', () => {
void loadReport();
});

void loadReport();
58 changes: 58 additions & 0 deletions app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OrangeHRM HR Manager Report</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=IBM+Plex+Mono:wght@400;500&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="./styles.css" />
</head>
<body>
<div class="page-shell">
<header class="hero">
<p class="eyebrow">OrangeHRM Demo Directory</p>
<h1>HR Manager Search Report</h1>
<p class="lede">
This local viewer renders the latest Playwright BDD artifact generated from the OrangeHRM directory search flow.
</p>
<div class="hero-meta">
<span id="jobTitleChip">Waiting for report</span>
<span id="generatedAt">No artifact loaded</span>
</div>
</header>

<main class="content-grid">
<section class="panel summary-panel">
<h2>Summary</h2>
<div class="summary-row">
<span>Total Matches</span>
<strong id="totalResults">0</strong>
</div>
<div class="summary-row">
<span>Artifact Path</span>
<strong>artifacts/hr-managers.json</strong>
</div>
<p class="helper-text">
Run the BDD suite first if this page shows no data.
</p>
</section>

<section class="panel list-panel">
<div class="panel-heading">
<h2>Employees</h2>
<button id="reloadButton" type="button">Reload Report</button>
</div>
<p id="statusMessage" class="status-message"></p>
<div id="employeeList" class="employee-list"></div>
</section>
</main>
</div>

<script src="./app.js" defer></script>
</body>
</html>
Loading