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: Hovering over mount in command log does not show component in AUT #24346

Merged
merged 17 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions npm/react/src/createMount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,6 @@ export const makeMountFn = (

internalMountOptions.render(reactComponent, el, reactDomToUse)

if (options.log !== false) {
Cypress.log({
name: type,
type: 'parent',
message: [message],
// @ts-ignore
$el: (el.children.item(0) as unknown) as JQuery<HTMLElement>,
consoleProps: () => {
return {
// @ts-ignore protect the use of jsx functional components use ReactNode
props: jsx.props,
description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
home: 'https://github.com/cypress-io/cypress',
}
},
}).snapshot('mounted').end()
}

return (
// Separate alias and returned value. Alias returns the component only, and the thenable returns the additional functions
cy.wrap<React.ReactNode>(userComponent, { log: false })
Expand All @@ -123,6 +105,23 @@ export const makeMountFn = (
// and letting hooks and component lifecycle methods to execute mount
// https://github.com/bahmutov/cypress-react-unit-test/issues/200
.wait(0, { log: false })
.then(() => {
Cypress.log({
name: type,
type: 'parent',
message: [message],
// @ts-ignore
$el: (el.children.item(0) as unknown) as JQuery<HTMLElement>,
consoleProps: () => {
return {
// @ts-ignore protect the use of jsx functional components use ReactNode
props: jsx.props,
description: type === 'mount' ? 'Mounts React component' : 'Rerenders mounted React component',
home: 'https://github.com/cypress-io/cypress',
}
},
}).snapshot('mounted').end()
})
)
// Bluebird types are terrible. I don't think the return type can be carried without this cast
}) as unknown as globalThis.Cypress.Chainable<MountReturn>
Expand Down
12 changes: 7 additions & 5 deletions npm/vue2/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,12 @@ export const mount = (
})
.then((win) => {
if (optionsOrProps.log !== false) {
Cypress.log({
name: 'mount',
message: [message],
}).snapshot('mounted').end()
Vue.nextTick(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd expect the nextTick to be wrapped within the chain so as to ensure the tick and log is captured before the next Cypress command is fired. You could convert this function to be async and await Vue.nextTick() as the end.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am not sure we need async/await - could just do it like this, right?

.then((win) => Vue.nextTick())
.then(() => {
  /* stuff */
})

If anyone was curious, under-the-hood nextTick is basically just Promise.resolve (with various fallbacks). It actually uses MutationObserver as a fallback, interestingly enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

As long as the .then(() => Vue.nextTick()) is done after the component creation I'm cool with it!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This sounds good. I've made the necessary changes on the latest commit

Cypress.log({
name: 'mount',
message: [message],
}).snapshot('mounted').end()
})
}

const localVue = createLocalVue()
Expand Down Expand Up @@ -410,7 +412,7 @@ export const mount = (

Cypress.vue = VTUWrapper.vm
Cypress.vueWrapper = VTUWrapper
})
}).wait(0, { log: false })
amehta265 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
51 changes: 51 additions & 0 deletions packages/app/cypress/e2e/runner/reporter-ct-mount-hover.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { fixtureDirs } from '@tooling/system-tests'

type ProjectDirs = typeof fixtureDirs

const PROJECTS: {projectName: ProjectDirs[number], test: string}[] = [
{ projectName: 'angular-15', test: 'app.component' },
amehta265 marked this conversation as resolved.
Show resolved Hide resolved
{ projectName: 'vueclivue2-configured', test: 'HelloWorld.cy' },
{ projectName: 'react-vite-ts-configured', test: 'App.cy' },
{ projectName: 'react18', test: 'App.cy' },
{ projectName: 'create-react-app-configured', test: 'App.cy' },
{ projectName: 'vueclivue3-configured', test: 'HelloWorld.cy' },
{ projectName: 'nuxtjs-vue2-configured', test: 'Tutorial.cy' },
]

for (const { projectName, test } of PROJECTS) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Tests are very thorough, and I know this is already ✔️ , but I wonder if we want to consider adding these to an existing test in the future? Scaffolding all these projects is pretty expensive (in terms of CI time) for something that could be exercised in one of the other tests we've got for the various frameworks.

describe(`CT Mount ${projectName}`, { viewportWidth: 1500, defaultCommandTimeout: 10000 }, () => {
beforeEach(() => {
cy.scaffoldProject(projectName)
cy.findBrowsers()
}),
it(`While hovering on Mount(), shows component on AUT for ${projectName}`, () => {
if (`${projectName}` === 'react18') {
cy.openProject(projectName, ['--config-file', 'cypress-vite.config.ts'])
cy.startAppServer('component')
cy.visitApp()
cy.contains(`${test}`).click()
cy.waitForSpecToFinish()
cy.get('.collapsible-header-inner:first').click().get('.command.command-name-mount > .command-wrapper').click().then(() => {
cy.get('iframe.aut-iframe').its('0.contentDocument.body').then(cy.wrap).within(() => {
amehta265 marked this conversation as resolved.
Show resolved Hide resolved
cy.get('[data-cy-root]').children().should('have.length.at.least', 1)
})
})
} else {
cy.openProject(projectName)
cy.startAppServer('component')
cy.visitApp()
cy.contains(`${test}`).click()
cy.waitForSpecToFinish()
cy.get('.command.command-name-mount > .command-wrapper').click().then(() => {
if (`${projectName}` === 'angular-15') {
cy.get('iframe.aut-iframe').its('0.contentDocument.body').children().should('have.length.at.least', 2)
} else {
cy.get('iframe.aut-iframe').its('0.contentDocument.body').then(cy.wrap).within(() => {
cy.get('[data-cy-root]').children().should('have.length.at.least', 1)
})
}
})
}
})
})
}