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

fix: remove last mounted component upon subsequent mount calls #24470

Merged
merged 11 commits into from
Nov 3, 2022

Conversation

ZachJW34
Copy link
Contributor

User facing changelog

Subsequent mount calls within the same test will remove the last mounted component from the DOM

Additional details

Calling mount multiple times in a single test had different behavior between frameworks. Some (properly) removed the element, some mounted multiple components and another threw an error.

This PR makes all of the frameworks behave consistently by destroying/removing the last component mounted if mount is called again within a test.

Steps to test

I relied on system-tests to test these changes, specifically the tests in component_testing_spec.ts. I've added/tweaked the mount.cy.{ts,js,tsx,jsx} tests for react,vue,svelte,angular to verify the behavior.

How has the user experience changed?

Screen.Recording.2022-10-31.at.11.35.40.AM.mov

PR Tasks

  • Have tests been added/updated?
  • Has the original issue (or this PR, if no issue exists) been tagged with a release in ZenHub? (user-facing changes only)
  • Has a PR for user-facing changes been opened in cypress-documentation?
  • Have API changes been updated in the type definitions?

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Oct 31, 2022

Thanks for taking the time to open a PR!

@cypress
Copy link

cypress bot commented Oct 31, 2022

Copy link
Contributor

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

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

Few comments, code seems good

function cleanup () {
activeFixture = null
// Not public, we need to call this to remove the last component from the DOM
getTestBed()['tearDownTestingModule']()
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think we need to be a bit defensive here? Eg

const teardown = getTestBed()['tearDownTestingModule']
if (!teardown) {
  throw Error('Could not teardown component. The version of Angular you are using may not be officially supported').
  // OR just return early?
  return
}

teardown()

Copy link
Contributor

Choose a reason for hiding this comment

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

Surprised TS isn't erroring here with "might be undefined" - maybe we should make the TS setting more strict.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like the idea of throwing an error here. Since this is something that might break in a minor, it's best to fail early and loud. The logic in tearDownTestingModule is important to guarantee clean state for the next tests so I'm ok with erroring in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ce2c587, also made the types more strict for npm/angular

Comment on lines 93 to 95
it("should mount", () => {
cy.mount(Counter);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
it("should mount", () => {
cy.mount(Counter);
});
it('should mount', () => {
cy.mount(Counter);
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ce2c587

system-tests/project-fixtures/vue/src/style.css Outdated Show resolved Hide resolved
@lmiller1990 lmiller1990 self-requested a review November 2, 2022 00:10
Copy link
Contributor

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

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

LGTM

try {
(getTestBed() as any).tearDownTestingModule()
} catch (e) {
throw new Error(`Failed to teardown component. The version of Angular you are using may not be officially supported, visit https://docs.cypress.io/guides/component-testing/component-framework-configuration for current Angular version support.`)
Copy link
Contributor

@rockindahizzy rockindahizzy Nov 2, 2022

Choose a reason for hiding this comment

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

Should this use an on link?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Damn you onLinks!!!

@ZachJW34
Copy link
Contributor Author

ZachJW34 commented Nov 2, 2022

@rockindahizzy added the onlinks here: https://github.com/cypress-io/cypress-services/pull/4937

Error thrown
Screen Shot 2022-11-02 at 4 05 47 PM

Copy link
Contributor

@marktnoonan marktnoonan left a comment

Choose a reason for hiding this comment

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

Did manual testing Vue, works great.

Looking at Percy, we have 3 snapshots that rely on mount not being cleaned up, to catch all the variations at once. I actually like this behavior from a billing perspective lol.

Not blocking, I'll make a PR into with suggested updates to these tests into this branch if it is still open at the time, or into the freature branch if we've already merged this.

A few other small observations/questions that don't block merging.

Screen Shot 2022-11-02 at 9 40 17 PM

Screen Shot 2022-11-02 at 9 45 46 PM

Screen Shot 2022-11-02 at 9 46 56 PM

@@ -33,6 +33,9 @@ export function mount (jsx: React.ReactNode, options: MountOptions = {}, rerende
Cypress.log({ name: 'warning', message })
}

// Remove last mounted component if cy.mount is called more than once in a test
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this comment only applicable in React 18 or should it be here as well?

// React by default removes the last component when calling render, but we should remove the root
// to wipe away any state

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Only applicable to 18, react17 doesn't have the concept of root but just a rerender into the same element.

Cypress.vueWrapper?.unmount()
const el = getContainerEl()
const cleanup = () => {
Cypress.vueWrapper?.unmount()
Copy link
Contributor

Choose a reason for hiding this comment

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

If there's no Cypress.vueWrapper that would indicate it's the first mount, so possibly we just return here instead of touching the DOM?

Actually wondered, as part of cleanup do we want to unset Cypress.vueWrapper and Cypress.vue? Probably pointless since mount will overwrite them & cleanup is always called before mount.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm going to remove the innerHtml = '', more consistent with other frameworks. I'll add the cleanup as well.

@@ -266,6 +265,10 @@ declare global {
}
}

const cleanup = () => {
Cypress.vueWrapper?.destroy()
Copy link
Contributor

Choose a reason for hiding this comment

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

Any need to do innerHTML = '' for the root el here? Curious why Vue 3 does it but Vue 2 does not

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ZachJW34 ZachJW34 merged commit f39eb1c into release/11.0.0 Nov 3, 2022
@ZachJW34 ZachJW34 deleted the zachw/remove-last-mounted-component branch November 3, 2022 17:19
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.

4 participants