FormsRefresh

HR application

Three Forms modules on Oracle's HR sample schema: LOGIN, CONSOLE and EMPLOYEES (master-detail blocks on tab pages, three lists of values, alerts, calls between forms, APEX links signed with a token).

Open the live migrated app Target: .NET 10 and PostgreSQL, the forms' windows, blocks, lists of values and alerts in the browser.

The live demos share one database per app: visitors see each other's changes, and the data resets to the scenario fixture every night.

Log in as alice / alice#123 (administrator) or bob / bob#123.

Original Forms source: github.com/astramieri/hr-app-forms at commit 5d6c227, MIT, copyright 2024 Angelo Stramieri licence.

Parity: 17 of 17 scenarios

Each scenario was recorded on the original and replayed against the migrated app. Three runs from a fresh database gave byte-identical diffs for every scenario; none has a defect. Open a scenario for its steps, screenshots of both apps, the golden record, the diff and its waivers.

ScenarioWhat it doesmatchtoleratedwaiveddefectunmappedThree runs
console-apexThe APEX button composes a URL with a signed token (COMPOSE_URL), shows it and calls WEB.SHOW_DOCUMENT.391300identical
console-logoutLog in as bob; LOGOUT erases the global and returns to LOGIN with NEW_FORM.440000identical
employees-apexThe block's APEX button and a row's Details button each compose an APEX URL with a signed token; the client host has no browser, so WEB.SHOW_DOCUMENT answers with FRM-92022. Closing EMPLOYEES ends its database session (OPEN_FORM with SESSION), which writes that session's PL/SQL coverage.65641000identical
employees-change-departmentMove an employee to another department through the DEPARTMENTS LOV and raise another employee's salary, then save. UPDATE_JOB_HISTORY records the old department for the first row and finds nothing to record for the second (Forms updates every column, so the trigger fires for both). Closing EMPLOYEES ends its database session, which writes that session's PL/SQL coverage.5511000identical
employees-change-jobChange an employee's job through the JOBS LOV and save; the UPDATE_JOB_HISTORY trigger records the old job. Closing EMPLOYEES ends its database session, which writes that session's PL/SQL coverage.5511000identical
employees-clearClear All with no change does nothing; after an edit CONFIRM_CLEAR asks, Cancel keeps it and OK discards it.9210000identical
employees-closeClosing EMPLOYEES with an unsaved change asks to commit (EXIT_FORM ASK_COMMIT); No returns to CONSOLE, whose close ends the session.4290000identical
employees-createCreate an employee with the three LOVs and save; PRE-INSERT takes the id from EMPLOYEES_SEQ.10463700identical
employees-deleteDelete an employee without history after confirming CONFIRM_DELETE; DELETE_RECORD and COMMIT_FORM.5520000identical
employees-delete-refusedDeleting an employee with job history is refused by ON-CHECK-DELETE-MASTER; a cancelled delete changes nothing.7980000identical
employees-detailsMove to another employee (the relations clear and requery the details) and show each tab page; Save with nothing changed does not commit.7980000identical
employees-openLog in as alice and open EMPLOYEES from CONSOLE; WHEN-NEW-FORM-INSTANCE queries the employees.1610000identical
employees-searchSearch employees by a name fragment (the first hit has no department, so its DEPARTMENT detail is not queried), Reset back to the full list, then Search with an empty field.6600100identical
login-closeClosing the LOGIN window (title-bar close box) runs WHEN-WINDOW-CLOSED, which ends the session.260000identical
login-failA wrong password raises ALERT_FAILURE (NO_DATA_FOUND in LOGIN.LOGIN); LOGIN stays open.500000identical
login-okLog in as alice; LOGIN opens CONSOLE with NEW_FORM, which shows the user name.360000identical
login-openOpen LOGIN and record its initial state (the prefix of the LOGIN locator check).200000identical
total7338102100

Tolerance policy: tolerance-policy.yaml.

Coverage of the original

Every trigger and program unit of the Forms modules, measured with Forms Runtime Diagnostics while the scenarios ran; database PL/SQL measured with DBMS_PLSQL_CODE_COVERAGE.

ModuleTriggersProgram unitsCoveredUnreachableBlocked
CONSOLE50500
EMPLOYEES1431700
LOGIN20200
total2132400

Decision branches: 32, of which 24 covered, 4 unreachable (retirement candidates) and 4 blocked. Database PL/SQL: 11 unit(s) in the coverage report, 13 of 13 blocks covered. Exit check: PASS.

Every branch with its class
Trigger or unitBranchClassScenarios or reason
LOGIN/LOGIN.LOGIN/WHEN-BUTTON-PRESSEDuser and password match - console openscoveredconsole-apex, console-logout, employees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search, login-ok
LOGIN/LOGIN.LOGIN/WHEN-BUTTON-PRESSEDno matching user - ALERT_FAILUREcoveredlogin-fail
CONSOLE/CONSOLE.EMPLOYEES/WHEN-BUTTON-PRESSEDEMPLOYEES not open - OPEN_FORMcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
CONSOLE/CONSOLE.EMPLOYEES/WHEN-BUTTON-PRESSEDEMPLOYEES already open - GO_FORMblockedNeeds the CONSOLE button pressed while EMPLOYEES is open. OPEN_FORM(ACTIVATE) puts the EMPLOYEES window over the console, and the way back is the FSAL "Window" menu, which is a client menu with no Forms name (LWMenu1); the runner only clicks named elements. Harness limit.
EMPLOYEES/BUTTONS.SAVE_BUTTON/WHEN-BUTTON-PRESSEDblock changed - commitcoveredemployees-change-department, employees-change-job, employees-create
EMPLOYEES/BUTTONS.SAVE_BUTTON/WHEN-BUTTON-PRESSEDnothing changed - no commitcoveredemployees-details
EMPLOYEES/BUTTONS.DELETE_BUTTON/WHEN-BUTTON-PRESSEDconfirmed - delete and commitcoveredemployees-delete
EMPLOYEES/BUTTONS.DELETE_BUTTON/WHEN-BUTTON-PRESSEDcancelled - nothing deletedcoveredemployees-delete-refused
EMPLOYEES/BUTTONS.CLEAR_BUTTON/WHEN-BUTTON-PRESSEDchanged, confirmed - changes discarded and requeriedcoveredemployees-clear
EMPLOYEES/BUTTONS.CLEAR_BUTTON/WHEN-BUTTON-PRESSEDchanged, cancelled - changes keptcoveredemployees-clear
EMPLOYEES/BUTTONS.CLEAR_BUTTON/WHEN-BUTTON-PRESSEDnothing changed - no questioncoveredemployees-clear
EMPLOYEES/EMPLOYEES/ON-CHECK-DELETE-MASTERjob history exists, delete refusedcoveredemployees-delete-refused
EMPLOYEES/EMPLOYEES/ON-CHECK-DELETE-MASTERno job history, delete goes aheadcoveredemployees-delete
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSmaster record NEW or INSERT - no detail querycoveredemployees-clear, employees-create
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSDEPARTMENT_ID set - department queriedcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSDEPARTMENT_ID null - no department querycoveredemployees-search
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSMANAGER_ID set - manager queriedcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-delete, employees-delete-refused, employees-details, employees-search
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSMANAGER_ID null - no manager querycoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSEMPLOYEE_ID set - history queriedcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILSEMPLOYEE_ID null on a queried record - no history queryunreachableEMPLOYEE_ID is the primary key of EMPLOYEES, so a queried record always has it; NEW and INSERT records return before this point.
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILScursor moved by the queries, returned to the start itemcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/EMPLOYEES/ON-POPULATE-DETAILScursor still on the start item after the queriesunreachableEvery relation is not deferred, so each detail query does GO_BLOCK to the detail and the cursor always leaves the master item; HISTORY is always queried (EMPLOYEE_ID is the key).
EMPLOYEES/unit:QUERY_MASTER_DETAILSrelation not deferred - GO_BLOCK and EXECUTE_QUERYcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/unit:QUERY_MASTER_DETAILSrelation deferred - SET_BLOCK_PROPERTY non-coordinatedunreachableNo relation of EMPLOYEES is deferred and nothing changes that at run time.
EMPLOYEES/unit:QUERY_MASTER_DETAILSGO_BLOCK to the detail failed - exception handlerblockedNeeds GO_BLOCK to a detail block to fail during coordination. The detail blocks have no PRE-BLOCK, WHEN-NEW-BLOCK-INSTANCE or validation that can refuse entry; no input found that makes it fail.
EMPLOYEES/unit:CHECK_PACKAGE_FAILUREprevious built-in succeededcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/unit:CHECK_PACKAGE_FAILUREprevious built-in failed - raise FORM_TRIGGER_FAILUREblockedCalled after GO_BLOCK and GO_ITEM in the coordination units; no input found that makes these fail (see the QUERY_MASTER_DETAILS exception branch).
EMPLOYEES/unit:CLEAR_ALL_MASTER_DETAILSa detail block holds rows - cleared without validationcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-search
EMPLOYEES/unit:CLEAR_ALL_MASTER_DETAILSevery detail block empty - nothing clearedcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-open, employees-search
EMPLOYEES/unit:CLEAR_ALL_MASTER_DETAILScursor moved by the clearing, returned to the start itemcoveredemployees-apex, employees-change-department, employees-change-job, employees-clear, employees-close, employees-create, employees-delete, employees-delete-refused, employees-details, employees-search
EMPLOYEES/unit:CLEAR_ALL_MASTER_DETAILSchanged detail block below the master - ask to commitunreachableDEPARTMENT, MANAGER and HISTORY allow no insert, update or delete, so a detail block is never CHANGED.
EMPLOYEES/unit:CLEAR_ALL_MASTER_DETAILSa detail block not cleared - raise FORM_TRIGGER_FAILUREblockedNeeds CLEAR_BLOCK(NO_VALIDATE) on a read-only detail block to leave rows behind; no input found that makes it fail.
Database PL/SQL units
UnitTypeBlocksCoveredClass
COMPOSE_URLFUNCTION33covered
GENERATE_TOKENFUNCTION55covered
VALIDATE_TOKENFUNCTIONNone0unreachable
ADD_JOB_HISTORYPROCEDURE11covered
INSERT_LOGPROCEDURENone0unreachable
SECURE_DMLPROCEDURENone0unreachable
APEX_TRG_01TRIGGERNone0unreachable
REQUESTS_TRG_01TRIGGERNone0unreachable
SECURE_EMPLOYEESTRIGGERNone0unreachable
UPDATE_JOB_HISTORYTRIGGER44covered
USERS_TRG_01TRIGGERNone0unreachable

Waivers

Source behaviour a customer would probably not replicate, proposed for the customer's decision. Each is pinned to the exact values it covers; the counts are values waived in the final diffs. File: waivers.yaml.

IdWaiverValuesReason
H1APEX links fail with FRM-92022 instead of opening the page13The APEX buttons (CONSOLE.APEX, BUTTONS.APEX_BUTTON, the EMPLOYEES.APEX row button) compose a signed APEX URL, show it on the message line and call WEB.SHOW_DOCUMENT(url, '_blank'). On the Forms 14.1.2 client this fails: Forms shows the alert "FRM-92022: cannot launch URL ... The BROWSE action is not supported on the current platform!" and the page never opens, so the source records an alert, alert focus and an extra window, and the user has to dismiss it. The target writes the same message and opens the URL in a new browser tab, which is what the code asks for. Replicating the failure would mean shipping a broken link. The message line (APEX URL with the token) is still compared.
H2Department tab keeps the previous department number8When the current employee has no department (a new record, or Kimberely Grant, whose DEPARTMENT_ID is NULL), Forms clears the DEPARTMENT detail block, yet DEPARTMENT_ID on the Department tab keeps showing the number of the department shown before (90, Executive) while name, address, city and region are blank. The number belongs to another employee's department; the target clears the whole tab.