Skip to content
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

Integrate new compat shallow renderer into Enzyme #233

Merged
merged 22 commits into from
Dec 20, 2022

Conversation

andrewiggins
Copy link
Member

@andrewiggins andrewiggins commented Dec 8, 2022

This PR adds a new CompatShallowRenderer that implements Enzyme's shallow renderer interface using the preact shallow rendering algorithm from #223. Usage of the new renderer is behind the useCompatShallowRendering flag.

index.d.ts Show resolved Hide resolved
src/Adapter.ts Show resolved Hide resolved
test/shared.tsx Show resolved Hide resolved
test/shared.tsx Outdated
Comment on lines 350 to 366
if (isNewShallowRender) {
allMethods.forEach(method => Test.prototype[method].resetHistory());
} else {
// Calling reset here not only resets call counts, but also any behaviors
// setup, such as `.returns(true)`. Calling reset here, removes our
// `.returns(true)` setup on shouldComponentUpdate, causing the method to
// return `undefined`. In shallow rendering, Enzyme spies on the return
// value of `sCU` and chooses to invoke lifecycle methods based on its
// return value. Because it returns `undefined` in this case, Enzyme skips
// invoking `cDU`.
//
// In the default shallow renderer, Preact invokes lifecycles. In this
// test, once `.reset()` is called, `.sCU` returns `undefined` and so
// enzyme does not invoke `cDU`. In a real test environment, cDU would be
// invoked twice. A simpler test that doesn't use spies can see this behavior.
allMethods.forEach(method => Test.prototype[method].reset());
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More context: The new shallow renderer does not invoke componentDidUpdate or componentDidMount. It relies on Enzyme to handle that. Without the change to resetHistory(), it fails this test because when reset() is used, shouldComponentUpdate returns undefined which Enzyme interprets to mean to not invoked componentDidUpdate.

If I understand this test correctly, I think the intention is to only reset the call counts and not to clear all stub returns, hence my change to call resetHistory(). However this breaks the test for the old shallow renderer because now it demonstrates how componentDidUpdate will be invoked twice (once by Preact and once by Enzyme). So I left that behavior as is for now.

@robertknight
Copy link
Member

I have approved the other PR. Please give me a ping when this is rebased.

Base automatically changed from shared-tests to master December 9, 2022 17:18
@andrewiggins
Copy link
Member Author

@robertknight PR is rebased and ready for review!

@andrewiggins
Copy link
Member Author

@robertknight Updated per our comment thread about adding a compat sub package. I've moved all the compat shallow renderer related code into this sub package to better isolate and encapsulate that logic.

I think in my next PR I'll add a new test example that uses the compat renderer as a way to check that we are properly packaging and exposing the compat renderer so it can be included (i.e. I haven't missed any files in the root package.json files field and the compat/package.json is properly setup. (If you prefer, I can do that in this PR. My thought was that this PR is big enough already, but also I can see an argument for including that test in here :) )

@robertknight
Copy link
Member

@robertknight Updated per our comment thread about adding a compat sub package. I've moved all the compat shallow renderer related code into this sub package to better isolate and encapsulate that logic.

Thanks @andrewiggins. I'm going to take a look this weekend.

Copy link
Member

@robertknight robertknight left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a few queries but this looks good in big picture terms. Are there other changes to come after this for the new shallow renderer?

CHANGELOG.md Outdated Show resolved Hide resolved
compat/README.md Show resolved Hide resolved
compat/package.json Show resolved Hide resolved
compat/test/CompatShallowRenderer_test.tsx Outdated Show resolved Hide resolved
src/Adapter.ts Show resolved Hide resolved
src/Adapter.ts Outdated Show resolved Hide resolved
src/Adapter.ts Outdated Show resolved Hide resolved
}

const appKey = 'app';
const wrapper = mount(<App key={appKey} />);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Searching the Enzyme codebase for references to getElement and getElements I only find it documented for the shallow rendering mode. Is this a mistake in the Enzyme docs?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh that's true. It appears to be. It is definitely implemented in their mount wrapper (source). As well as tested (source). I think I was researching what the right behavior here is for the shallow renderer and ended up writing the test for the mount renderer to compare and figured I'd add them. But if you don't think they are useful, happy to remove these.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the missing documentation is probably an oversight on Enzyme's side. Would you mind filing an issue against the Enzyme repo and referencing it here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test/shared.tsx Outdated Show resolved Hide resolved
Co-authored-by: Robert Knight <robertknight@gmail.com>
Copy link
Member Author

@andrewiggins andrewiggins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! I have no other big work items for the new shallow renderer planned at the moment, though I expect there will be incremental bug fixes as we start to use it at work.

I think with this change we have a good release candidate to get the first version of the new compat renderer out there.

compat/package.json Show resolved Hide resolved
compat/README.md Show resolved Hide resolved
src/Adapter.ts Outdated Show resolved Hide resolved
src/Adapter.ts Outdated Show resolved Hide resolved
compat/test/CompatShallowRenderer_test.tsx Outdated Show resolved Hide resolved
}

const appKey = 'app';
const wrapper = mount(<App key={appKey} />);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh that's true. It appears to be. It is definitely implemented in their mount wrapper (source). As well as tested (source). I think I was researching what the right behavior here is for the shallow renderer and ended up writing the test for the mount renderer to compare and figured I'd add them. But if you don't think they are useful, happy to remove these.

@@ -60,6 +80,23 @@ export default class Adapter extends EnzymeAdapter {
// Work around a bug in Enzyme where `ShallowWrapper.getElements` calls
// the `nodeToElement` method with undefined `this`.
this.nodeToElement = this.nodeToElement.bind(this);

if (this.preactAdapterOptions.ShallowRenderer) {
this.isFragment = node => node?.type === Fragment;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! I wasn't entirely sure what would happen. If I enable it for all renderers, our test suite still passes. I believe it won't impact our existing renderers cuz we already remove fragments from the RST tree in rstNodeFromVNode. I was just being more conservative here, but it appears to be safe for us to enable for all renderers. Would you like me to do that?

@robertknight
Copy link
Member

I think with this change we have a good release candidate to get the first version of the new compat renderer out there.

I agree. Let's get this landed. We don't have a convention in this repo for publishing pre-releases for early testing. What do other Preact projects do?

@andrewiggins andrewiggins merged commit 9d7749b into master Dec 20, 2022
@andrewiggins andrewiggins deleted the new-shallow-renderer branch December 20, 2022 19:26
@andrewiggins
Copy link
Member Author

I don't think we have any formal guidelines. In the past we've used -experimental, -alpha, -beta, and -rc tags when making major changes.

Actually, since everything here is behind flags, maybe we don't need to do a release candidate or pre-release. We could just do a minor release? Or would you rather do some sort of pre-release first to test changes? If so, perhaps we could use the -rc or -beta tag?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants