Purpose
Create an employee with supplied details in EA App and return whether the server accepted it as a non-duplicate employee. The skill also supports directly verifying whether an employee record is present by name.
When to Use
Use this skill when an authenticated profile must create or verify an employee on eaapp.somee.com. For creation, the caller supplies Name, Age, Salary, DurationWorked, Email, and optionally Grade. For verification-only requests, the caller supplies an employee name. Use made-up values only when the caller explicitly requests test data.
Workflow
For verification-only, navigate directly to
https://eaapp.somee.com/Employee?searchTerm={url-encoded-name}and run the extractor in step 5. Treatfound: trueas evidence that a matching row is listed, not as proof of a successful creation event.For creation, navigate directly to
https://eaapp.somee.com/Employee/Createwith the requested authenticated browser profile.In one page evaluation, first verify authentication, resolve the requested Grade label to its actual option value when supplied, fill the form using the native value setters, and submit with
form.requestSubmit(). If navigation landed on/Account/Loginor/Account/AccessDenied, report that the profile lacks the required authentication or authorization instead of submitting.
(() => {
const auth = {
url: location.href,
loggedIn:
!!document.querySelector(
'form[action*="Logout" i], form[action*="LogOff" i]',
) || /Hello\s+[^!]+!/i.test(document.body?.innerText || ""),
};
if (/\/Account\/Login(?:[\/?#]|$)/i.test(location.pathname))
return { ...auth, submitted: false, error: "Not logged in" };
if (/\/Account\/AccessDenied(?:[\/?#]|$)/i.test(location.pathname))
return { ...auth, submitted: false, error: "Access denied" };
const values = {
Name: "{name}",
Age: "{age}",
Salary: "{salary}",
DurationWorked: "{duration-worked}",
Grade: "{grade-or-empty-string}",
Email: "{email}",
};
const nameControl = document.getElementById("Name");
const form = nameControl?.form;
if (!form) throw new Error("Create form not found (no #Name field on page)");
const gradeControl = document.getElementById("Grade");
if (!gradeControl) throw new Error("Grade control not found");
const requestedGrade = String(values.Grade || "").trim();
const gradeOption = requestedGrade
? Array.from(gradeControl.options).find(
(o) =>
o.value === requestedGrade ||
o.textContent.trim().toLowerCase() === requestedGrade.toLowerCase(),
)
: Array.from(gradeControl.options).find((o) => o.value !== "");
const gradeValue = gradeOption?.value;
if (!gradeValue) throw new Error("No usable Grade option found");
const inputSetter = Object.getOwnPropertyDescriptor(
HTMLInputElement.prototype,
"value",
).set;
const selectSetter = Object.getOwnPropertyDescriptor(
HTMLSelectElement.prototype,
"value",
).set;
for (const [id, value] of Object.entries({ ...values, Grade: gradeValue })) {
const control = document.getElementById(id);
if (!control || value == null || value === "")
throw new Error(`Missing required control or value: ${id}`);
(control.tagName === "SELECT" ? selectSetter : inputSetter).call(
control,
String(value),
);
for (const event of ["input", "change", "blur"])
control.dispatchEvent(new Event(event, { bubbles: true }));
}
if (!form.checkValidity()) throw new Error("Form invalid after fill");
const result = {
...auth,
submitted: true,
formAction: form.action,
gradeRequested: requestedGrade || null,
gradeUsed: gradeValue,
gradeLabel: gradeOption.textContent.trim(),
values: Object.fromEntries(
Object.keys(values).map((id) => [id, document.getElementById(id).value]),
),
};
form.requestSubmit();
return result;
})();Wait for navigation (
waitForNavigation, ~15000 ms). A successful creation redirects tohttps://eaapp.somee.com/Employeewith the session still authenticated. Landing back on/Employee/Createmeans validation failed—extract.field-validation-error/.validation-summary-errorstext. Landing on the home page logged out means the wrong form was submitted.Verify the created name with one direct navigation to
https://eaapp.somee.com/Employee?searchTerm={url-encoded-name}, then run this extractor and requirefound: true:
(() => {
const query = new URLSearchParams(location.search).get("searchTerm") || "";
const normalized = query.trim().toLowerCase();
const rows = Array.from(document.querySelectorAll("table tbody tr")).map(
(tr, index) => {
const cells = Array.from(tr.querySelectorAll("th, td")).map((cell) =>
cell.innerText.trim(),
);
return { index, cells, text: cells.join(" | ") };
},
);
const matches = normalized
? rows.filter((row) => row.text.toLowerCase().includes(normalized))
: [];
return {
url: location.href,
title: document.title,
query,
totalRows: rows.length,
found: matches.length > 0,
matches,
};
})();Run verification while authenticated: the anonymous list view can render “No employees found” even when the record exists, so a logged-out search is not evidence of failed creation.
Site-Specific Gotchas
- The navbar Logout form is the first
<form>in document order on every authenticated page. Generic form selectors can submit/Account/Logout; always anchor form selection on#Name(document.getElementById('Name').formorform:has(#Name)). - The creation page is directly reachable at
/Employee/Create; no homepage or employee-list interaction is required. - Unauthenticated requests redirect to
/Account/Login?ReturnUrl=%2FEmployee%2FCreate. Check for that redirect or authenticatedHello ...!/ Logout markers before submitting. - A profile may reach
/Account/AccessDenied?ReturnUrl=%2FEmployee%2FCreate; creating employees requires the admin role. Do not attempt registration or credential creation as a workaround. - Form controls use IDs
Name,Age,Salary,DurationWorked,Grade, andEmail. #DurationWorkedis a number input that can silently drop values assigned by ordinary keystrokes; use native prototype setters and dispatchinput,change, andblur.Grademust not be empty. Observed option values are numeric (Junior=1,Middle=2,Senior=3,C-Level=4); resolve labels against option text and submit the matched value. If omitted, select the first nonempty option.- Submit with
form.requestSubmit()on the#Name-anchored form so antiforgery tokens and cookies are included. Avoid real mouse clicks because ad overlays can intercept them and navigate to an ad page. - Employee lookup uses
/Employee?searchTerm={url-encoded-name}. Results aretable tbody tr; extract boththandtdtext rather than assuming a fixed column count. - The form selector and field IDs are stable in the observed page; re-check them if the site changes its markup.
Expected Output
For creation, return the pre-submit evaluation object (authentication status, formAction, requested and submitted Grade values, filled field values, and submitted) followed by post-navigation verification. Report success only when the search extractor returns found: true for the new employee while authenticated. For verification-only requests, return the search extractor object with query, totalRows, found, and matching row cell arrays. Report login or access-denied failures explicitly. Do not expose credentials or hidden form-token values.