QA Practice Portal
Test data and selectors
Demo accounts
| Password | Role | Use it for | |
|---|---|---|---|
student@qa.test | Password123 | student | The main happy path. Seeded with 4 enrolments, 3 tickets and 5 notifications. |
admin@qa.test | Admin@123 | admin | Unlocks the three admin screens. |
instructor@qa.test | Teach@123 | instructor | A signed-in role that must not see the admin area. |
suspended@qa.test | Password123 | student | Correct password, but sign-in is always refused. |
dana@qa.test, miguel@qa.test | Password123 |
student | Extra rows for admin list filtering. |
Locator conventions
Every interactive element carries a data-testid. Prefer it over CSS classes or XPath
position - the styling will change, the test ids will not.
// Playwright
await page.getByTestId('input-email').fill('student@qa.test');
await page.getByTestId('btn-login').click();
// Selenium (Java)
driver.findElement(By.cssSelector("[data-testid='input-email']")).sendKeys("student@qa.test");
// Cypress
cy.get('[data-testid=btn-login]').click();
Naming pattern
input-*,select-*,textarea-*,checkbox-*,radio-*,range-*- form controlsbtn-*- buttons; row-level buttons end with the record id, e.g.btn-enroll-3link-*,nav-*,tab-*,filter-*- navigation*-row,*-card,*-item- repeating elementserror-<field>- the inline validation message for that fieldflash-success/flash-danger/flash-warning/flash-info- page-level messages, with the text inflash-messagetoast- transient message, auto-hides after 4 secondsempty-state- shown by every list when there is nothing to display
Synchronisation hooks
body[data-app-ready="true"]- set on window load[data-testid="results-summary"]carriesdata-total,data-pageanddata-total-pages[data-testid="pagination-*"]carriesdata-current-page/data-total-pages- Rows expose their business key:
data-course-code,data-ticket-ref,data-user-email - Forms with client validation set
data-validation="passed|failed"on submit
Page map
| Path | Page | What there is to test |
|---|---|---|
login.php |
Sign in | Valid / invalid credentials, suspended account, lockout after 5 failures |
register.php |
Registration | Field validation, duplicate email, password rules, terms checkbox |
forgot-password.php |
Forgot password | Generates a reset link on screen (no mail server needed) |
reset-password.php |
Reset password | Valid token, expired token, mismatched passwords |
dashboard.php |
Dashboard | Stat cards, progress bar, quick enrol, activity timeline |
courses.php |
Course catalog | Search, category / level / price filters, sorting, paging, grid vs table |
course.php?id=1 |
Course detail | Enrol, drop with a confirm modal, progress slider, seat counting |
my-courses.php |
My courses | Status tabs, progress updates, drop, re-enrol, certificate |
certificate.php |
Certificate | Only for completed courses; has a real file download |
tickets.php |
Support tickets | Create in a modal, search, filter, sort, page, delete with confirm |
ticket.php?id=1 |
Ticket detail | Replies, status workflow, permission rules, delete |
notifications.php |
Notifications | Mark read / unread, mark all, delete, clear all, unread badge |
profile.php |
Profile | Tabs, validation, avatar upload, change password |
playground.php |
QA playground | Alerts, waits, frames, drag and drop, shadow DOM, status codes |
admin/users.php |
Admin: users | Search, role change, suspend, create, delete (admin only) |
admin/courses.php |
Admin: courses | Create / edit in one modal, publish toggle, delete guard |
admin/tickets.php |
Admin: tickets | Bulk status changes with select-all checkbox |
Deliberate behaviours worth a test
- Five failed sign-ins lock the form for 60 seconds, and the message counts down the attempts left.
suspended@qa.testgets a different message from a wrong password - assert on both.- Registering with an existing email is rejected server-side even if the client check is bypassed.
- Enrolling twice is refused; dropping and re-enrolling keeps the old progress.
- Setting progress to 100% flips the enrolment to completed and unlocks the certificate.
- A certificate request for an unfinished course redirects back with a warning.
- Resolved and closed tickets refuse new replies.
- A student can only move a ticket to Open or Closed; the other states need an admin.
- Opening another user's ticket by id redirects with a permission error.
- A non-admin hitting
admin/*is bounced to the dashboard with a message. - Admins cannot suspend, delete or demote their own account.
- A course with active enrolments cannot be deleted - unpublish it instead.
- Every destructive action goes through a confirm modal, and cancelling really does cancel.
- Every form is CSRF-protected: a stale token produces a visible "session expired" message.
Resetting the data
Put the database back to its seeded state before a suite run:
php C:\xampp\htdocs\theme\app\install.php
Or open install.php in a browser.
It only touches the qa_practice database, and it is disabled on the live host unless
QA_INSTALL_KEY is set. The terms and conditions for this sandbox are simple: it is a
practice target, so nothing you do here matters.
A sandbox built for practising UI test automation · Test data & selectors