-
Notifications
You must be signed in to change notification settings - Fork 392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: use more helpful error message for invalid render() return value @W-14785069 #3943
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this error message can be more effective if we target the root cause of the error.
I would suggest adding a logError
call to the invokeComponentRenderMethod
function here:
return renderInvocationSuccessful ? evaluateTemplate(vm, html!) : []; |
At this point in the code, we know if html
is undefined
(or some other invalid value). We can provide an error at the soonest possible moment, which would help a component author trying to use breakpoints in DevTools to debug.
BTW the reason I recommend logError
rather than throwing an Error
is that there may be some cases where a component author is calling render()
but would not reach the assert.isTrue
in template.ts
. E.g. they may be invoking render()
themselves manually. (It sounds strange, but we've seen component authors do stranger stuff.) So if we threw an Error
, we would produce a new failure condition that a component might not have hit before (i.e. a breaking change).
The reason I recommend logError
rather than logWarn
is that the yellow text may get lost in a sea of other warnings, whereas the red text would stand out, and would be printed before the red text for the template.ts
assert.isTrue
message. (This error message doesn't necessarily need to change; it is still accurately reporting the error it's hitting.)
I'm a bit confused by this. Your suggestion is to add the error to In any case, the conditional check already exists in Additionally, I think that a single error ("bad template") would ideally have a single error message, which should contain sufficient context to understand the error. Splitting the context across messages feels suboptimal, but if we want to keep the original thrown error message for backwards compatibility, then I guess multiple messages is really the only way to go. |
@wjhsf You're right, I just double-checked the code; I didn't realize that In that case no worries, let's go with your suggestion of improving the error message. Could you please also add a Karma test to confirm that the error is thrown in dev mode? We have a custom Jasmine matcher called |
it('throws an error when render() returns an invalid value', () => { | ||
const elm = createElement('x-render-invalid', { is: RenderInvalid }); | ||
expect(() => document.body.appendChild(elm)).toThrowErrorDev( | ||
Error, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Error, |
You don't need to assert the Error
class if you're just checking for a generic Error
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- `toThrowErrorDev(Error, message)`: `expect` a function to throw an error with a specific Error constructor and a specific message. |
Should update this, then, at some point...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops yeah, that's wrong. The message can be a regex or a string as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ak, I just realized you will need toThrowCallbackReactionErrorDev
because of native lifecycle. You can see why detailed here (scroll to "New error behavior").
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one small nit
FWIW, we mostly use "observable change" to mean "something that might break a customer in an inadvertent way." This one doesn't really pass that small test for me, since a customer would have to 1) catch the error and assert something about the error message, and 2) only in dev mode. We should probably change the template to just say "breaking/observable change," since that's what we really care about. |
packages/@lwc/integration-karma/test/component/LightningElement.render/index.spec.js
Outdated
Show resolved
Hide resolved
The `isTemplateRegistered` check inside `runWithBoundaryProtection` is equivalent, but more robust, and with a more clear error message.
The tests are failing:
|
an undefined template cannot be registered, so the `isTemplateRegistered` check is sufficient
Details
Pretty much what it says on the tin. I just reused a pre-existing error message:
lwc/packages/@lwc/engine-core/src/framework/template.ts
Lines 250 to 252 in a1831c1
Fixes #3924.
Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
GUS work item
W-14785069