-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
feat(pretty-format): Enable filtering of children in DOMElement #11130
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
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.
changelog entry? 🙂
This makes sense to me, but possibly something that should be mentioned in the readme? Dropping empty strings might be unexpected, dunno?
Will do.
This would only change existing behavior if people had custom plugins that handle an Element or CommentNode. |
right! that seems somewhat unlikely |
child !== null && | ||
(child as Node).nodeType !== NodeTypeTextNode | ||
) { | ||
// A plugin serialized this Node to '' meaning we should ignore it. |
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.
Hmm, I'm not so excited about taking away the ability of plugins to output empty text for a node, esp. in a breaking way. Would it be an option to allow returning null
instead?
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.
Hmm, I'm not so excited about taking away the ability of plugins to output empty text for a node, esp. in a breaking way.
My question would be: Why is that desired? Why write a plugin that takes a Node, serializes it to an empty string but also expect that empty string to be included in the snapshot.
Would it be an option to allow returning null instead?
I've tried this route but it propagated the possibly null
return all the way up so that other packages started to break.
I'll check again if we can change the boundaries but so far it seemed there are too many places that are accidentally coupled.
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'm not saying I have a concrete use case, but I know how many usages are out there pretty-printing element trees that are abstractions over HTML (if you need a horrifying example, take a look at 'ExtReact'). If in just one of them one renders plain text not with string children, but with createElem('Label', {text: ''})
, and their pretty printer converts the custom component language to the actual HTML, it will now no longer print the right representation of the element tree. With something used in as many wildly different tech stacks as Jest is, it is bound to break someone.
I would follow principle of least surprise — if an actual ''
text child is printed as an empty (except indented) line, you would expect a child that is mapped to ''
by the printer to behave the same. I don't know the empty string to typically signalize omission in other contexts either.
Regarding an explicit omission return value, we would want that limited specifically to printChildren
, because while printing children you can omit one, not in all other contexts.
I would expect that changing the type of printChildren
s printer
argument to something like the following would work?
type NullablePrinter = (...args: Parameters<Printer>) => ReturnType<Printer> | null
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.
Actually, I've just looked at the way you implemented your plugin, and this would not really help you because you are not in control of the printChildren
call, instead you rely on the standard DOMElement
or other plugin to make that call, passing the standard printer along which will then delegate to your plugin. :/
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 believe we have both been thinking about this the wrong way.
Printing
<div>
${print('asdf')}
${print('')}
</div>
and expecting the print('')
to be able to remove the whole third line is like printing
Object {
a: ${print(42)}
b: ${print(null)}
}
and expecting the print(null)
to be able to remove the whole third line for a toEqualIgnoringNulls()
matcher.
print('')
at top level should have the same result as print('')
in an element child, and print('')
at top level does not return a zero-line string either (because a zero-line string is not a thing, it would have -1 line breaks in it).
I think what should really be done to omit children from the output is not pass them into a printer in the first place. Replace the DOMElement plugin with a plugin under your control, that clones the node, throws out any children you don't want, then pass it to the DOMElement plugin to reuse its code. Let me know if this works for you.
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.
Actually, I've just looked at the way you implemented your plugin, and this would not really help you because you are not in control of the
Did you see the test added?
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.
Yes, the sentence you quoted referred to the previous comment, not to the implementation in this PR.
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 don't understand why you can say the current implementation doesn't help me when the test that uses the new implementation is exactly my desired outcome.
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.
Again, I am not saying what you implemented here does not work for you, I am aware it does. The second of the three comments says that what I suggested in the second half of the first comment actually would not work for you after I reconsidered it.
For why this change will lead to surprising behavior, see the first half of my first comment.
For an alternative solution that I believe would work without introducing this surprising behavior, see my third comment.
|
||
it('filters children', () => { | ||
const div = document.createElement('div'); | ||
|
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.
If possible I think it would be easier to compare this to the expected
if this was being constructed via
div.innerHTML = `...`
We're just going to fork the |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
Allow ignoring "noise" in the DOM in
pretty-format
Given
I want to be able to pretty-format only the "relevant" parts:
"relevant" means the parts that the tested code controls. Some testing frameworks (e.g. mocha or karma) insert script tags and comments which take up considerable space.
Test plan