Five posts in, you can write form scripts that handle events, field logic, lookups, subgrids, Web API calls, and even agent handoffs. None of that matters much if you can't quickly tell why a script isn't working, or catch it breaking before a user does. This post is about the workflow around the code — debugging, logging, and a lightweight way to test the logic outside the form entirely.
Debugging in the Browser
Skip alert() debugging. Open dev tools (F12), go to Sources, and find your web resource under the model-driven app's origin (usually nested under something like /webresources/). Set a real breakpoint by clicking the line number, then trigger the event from the form — execution will pause there with full access to inspect formContext, step through, and watch variables change.
function onChangeHandler(executionContext) {
debugger; // pauses here automatically when dev tools are open
var formContext = executionContext.getFormContext();
// ...
}
A Lightweight Logging Pattern
console.log calls scattered through production code get noisy and get left in by accident. A small wrapper keeps things consistent and easy to strip out or redirect later:
var Logger = {
enabled: false, // flip on only while diagnosing an issue
info: function (message, data) {
if (Logger.enabled) console.log("[Form Script] " + message, data || "");
},
error: function (message, error) {
console.error("[Form Script] " + message, error);
// optionally: send to Application Insights or a Dataverse log table here
}
};
// Usage
Logger.info("Status changed", formContext.getAttribute("statuscode").getValue());
Errors always log regardless of the flag — you want those visible in production. Informational logs stay quiet unless you're actively debugging.
Common Runtime Errors and What They Actually Mean
- "Cannot read properties of undefined/null (reading 'getValue')" —
getAttribute()returned null, almost always because that field isn't on the current form. Always check before calling methods on it. - "formContext.getControl(...).setVisible is not a function" — you're calling a control method on an attribute, or vice versa. Attributes hold values; controls are the UI.
- Nothing happens, no error at all — usually the event isn't registered correctly (check "Pass execution context as first parameter" is ticked), or the library isn't added to this particular form.
- Works in the maker portal preview, fails for users — security role differences. Test with a real (non-admin) user's role before calling it done.
Unit Testing with Jest (Mocking Xrm)
You don't need a live environment to test pure logic. Extract the decision-making into a plain function and mock the pieces of formContext it touches:
// discountLogic.js - the logic under test, extracted from the form script
function needsDiscountReason(discountPercent, customerType) {
return discountPercent > 10 && (customerType === 1 || customerType === 2);
}
module.exports = { needsDiscountReason };
// discountLogic.test.js
const { needsDiscountReason } = require("./discountLogic");
test("requires a reason above 10% for customer types 1 and 2", () => {
expect(needsDiscountReason(15, 1)).toBe(true);
expect(needsDiscountReason(15, 3)).toBe(false);
expect(needsDiscountReason(5, 1)).toBe(false);
});
This won't test the Dataverse integration itself, but it catches logic bugs instantly, without opening a browser — and it's the part of your script most likely to have an off-by-one or wrong-operator bug.
A Quick Smoke-Test Checklist Before You Publish
- Test on a new, unsaved record as well as an existing one
- Test with a non-administrator security role, not just your own
- Test on the mobile app if the form is used there
- Clear the browser cache or hard-refresh — stale web resource caching hides real bugs
- Check the console for errors even when the feature "looks" like it worked
Common Pitfalls
- Leaving debug logging on in production. Flip the Logger flag off (or gate it behind a config value) before publishing.
- Testing only the happy path. Try blank fields, unexpected option set values, and records that predate the script.
- Trusting the maker portal preview alone. It often runs with elevated privileges the real users won't have.
Wrapping Up
A script that works once in your own testing isn't the same as a script that's actually reliable. Debugging properly, logging deliberately, and testing the logic outside the form catches the bugs before your users do — which matters even more once your scripts start calling out to Web APIs and agents that can fail in their own ways too.
No comments:
Post a Comment