Skip to content

Commit

Permalink
chore: pass slideshow cohort to cloud CTAs for Debug (#26077)
Browse files Browse the repository at this point in the history
  • Loading branch information
warrensplayer authored Mar 10, 2023
1 parent 9d252e0 commit 9c98b5e
Show file tree
Hide file tree
Showing 10 changed files with 151 additions and 86 deletions.
17 changes: 17 additions & 0 deletions packages/app/src/debug/empty/DebugEmptyStates.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import DebugNoProject from './DebugNoProject.vue'
import DebugNoRuns from './DebugNoRuns.vue'
import DebugLoading from './DebugLoading.vue'
import DebugError from './DebugError.vue'
import DebugEmptyView from './DebugEmptyView.vue'
import { useLoginConnectStore } from '@packages/frontend-shared/src/store/login-connect-store'
import { DebugEmptyView_RecordEventDocument, DebugEmptyView_SetPreferencesDocument, UseCohorts_DetermineCohortDocument, _DebugEmptyViewFragment, _DebugEmptyViewFragmentDoc } from '../../generated/graphql-test'
import { DEBUG_SLIDESHOW } from '../utils/constants'
Expand Down Expand Up @@ -58,6 +59,22 @@ function mountWithGql (component: JSX.Element, gqlOptions?: { debugSlideshowComp
}

describe('Debug page empty states', () => {
context('empty view', () => {
it('renders with slot', () => {
const slotVariableStub = cy.stub().as('slot')

mountWithGql(
<DebugEmptyView title="My Title">
{{
cta: slotVariableStub,
}}
</DebugEmptyView>,
)

cy.get('@slot').should('be.calledWith', { utmContent: Cypress.sinon.match.string })
})
})

context('not logged in', () => {
it('renders', () => {
const loginConnectStore = useLoginConnectStore()
Expand Down
5 changes: 4 additions & 1 deletion packages/app/src/debug/empty/DebugEmptyView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
</ExternalLink>
</div>
</div>
<slot name="cta" />
<slot
name="cta"
:utm-content="selectedCohort?.cohort"
/>
</div>
<Slideshow
v-if="step !== undefined && steps"
Expand Down
7 changes: 5 additions & 2 deletions packages/app/src/debug/empty/DebugNoProject.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
:slideshow-campaign="DEBUG_SLIDESHOW.campaigns.connectProject"
help-link-href="https://on.cypress.io/adding-new-project"
>
<template #cta>
<CloudConnectButton utm-medium="Debug Tab" />
<template #cta="slotProps">
<CloudConnectButton
utm-medium="Debug Tab"
:utm-content="slotProps.utmContent"
/>
</template>
</DebugEmptyView>
</template>
Expand Down
7 changes: 5 additions & 2 deletions packages/app/src/debug/empty/DebugNotLoggedIn.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
:slideshow-campaign="DEBUG_SLIDESHOW.campaigns.login"
help-link-href="https://on.cypress.io/debug-page"
>
<template #cta>
<CloudConnectButton utm-medium="Debug Tab" />
<template #cta="slotProps">
<CloudConnectButton
utm-medium="Debug Tab"
:utm-content="slotProps.utmContent"
/>
</template>
</DebugEmptyView>
</template>
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/debug/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const DEBUG_SLIDESHOW = {
connectProject: 'Debug Connect Project Empty State',
recordRun: 'Debug Record Run Empty State',
},
medium: 'Debug tab',
medium: 'Debug Tab',
} as const

export type DebugSlideshowCampaigns = ValueOf<typeof DEBUG_SLIDESHOW['campaigns']>
11 changes: 10 additions & 1 deletion packages/app/src/runs/CloudConnectButton.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@ describe('<CloudConnectButton />', { viewportHeight: 60, viewportWidth: 400 }, (

cy.contains('button', 'Connect a Cypress Cloud project').click()

cy.get('@openLoginConnectModal').should('have.been.calledWith', { utmMedium: 'testing' })
cy.get('@openLoginConnectModal').should('have.been.calledWith', { utmMedium: 'testing', utmContent: undefined })
})

it('uses the store to open the Login Connect modal with utmContent', () => {
loginConnectStore.openLoginConnectModal = cy.spy().as('openLoginConnectModal')
cy.mount(() => <div class="h-screen"><CloudConnectButton utmMedium="testing" utmContent="content"/></div>)

cy.contains('button', 'Connect a Cypress Cloud project').click()

cy.get('@openLoginConnectModal').should('have.been.calledWith', { utmMedium: 'testing', utmContent: 'content' })
})
})
})
3 changes: 2 additions & 1 deletion packages/app/src/runs/CloudConnectButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
:class="props.class"
:prefix-icon="user.isLoggedIn ? ChainIcon : CypressIcon"
prefix-icon-class="icon-dark-white icon-light-transparent"
@click="openLoginConnectModal({ utmMedium: props.utmMedium })"
@click="openLoginConnectModal({ utmMedium: utmMedium, utmContent: utmContent })"
>
{{ user.isLoggedIn ? t('runs.connect.buttonProject') : t('runs.connect.buttonUser') }}
</Button>
Expand All @@ -24,6 +24,7 @@ const { t } = useI18n()
const props = defineProps<{
class?: string
utmMedium: string
utmContent?: string
}>()
</script>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LoginConnectModalsContentFragmentDoc } from '../generated/graphql-test'
import { Auth_LoginDocument, LoginConnectModalsContentFragmentDoc } from '../generated/graphql-test'
import LoginConnectModalsContent from './LoginConnectModalsContent.vue'
import { CloudUserStubs } from '@packages/graphql/test/stubCloudTypes'
import { SelectCloudProjectModal_CreateCloudProjectDocument } from '../generated/graphql'
Expand All @@ -7,96 +7,118 @@ import { useLoginConnectStore } from '../store/login-connect-store'

describe('<LoginConnectModalsContent />', () => {
context('when user is logged out', () => {
it('shows login modal', () => {
const { openLoginConnectModal } = useLoginConnectStore()

cy.mountFragment(LoginConnectModalsContentFragmentDoc, {
onResult: (result) => {
result.cloudViewer = null
},
render: (gqlVal) => {
return <LoginConnectModalsContent gql={gqlVal} />
},
})
[undefined, 'testContent'].forEach((content) => {
it(`shows login modal with utmContent: ${content}`, () => {
const { openLoginConnectModal } = useLoginConnectStore()

cy.mountFragment(LoginConnectModalsContentFragmentDoc, {
onResult: (result) => {
result.cloudViewer = null
},
render: (gqlVal) => {
return <LoginConnectModalsContent gql={gqlVal} />
},
})

cy.contains('Log in to Cypress')
.should('not.exist')
.then(() => {
openLoginConnectModal({ utmMedium: 'testing', utmContent: content })

cy.contains('Log in to Cypress').should('be.visible')
})

cy.contains('Log in to Cypress')
.should('not.exist')
.then(() => {
openLoginConnectModal({ utmMedium: 'testing' })
const loginStub = cy.stub().as('createProjectStub')

cy.contains('Log in to Cypress').should('be.visible')
cy.stubMutationResolver(Auth_LoginDocument, (defineResult, variables) => {
loginStub(variables)

return defineResult({} as any)
})

cy.contains('button', 'Log in')
.click()
.then(() => {
expect(loginStub.lastCall.args[0]).to.deep.eq({
utmSource: 'Binary: Launchpad',
utmMedium: 'testing',
utmContent: content || null,
})
})
})
})
})

context('when user is logged in', () => {
it('shows "Create Project" state if project is not set up', () => {
const { openLoginConnectModal, setUserFlag, setProjectFlag } = useLoginConnectStore()

setUserFlag('isLoggedIn', true)
setUserFlag('isMemberOfOrganization', true)
setUserFlag('isOrganizationLoaded', true)
setProjectFlag('isConfigLoaded', true)
setProjectFlag('isProjectConnected', false)

cy.mountFragment(LoginConnectModalsContentFragmentDoc, {
onResult: (result) => {
result.cloudViewer = { ...CloudUserStubs.me,
firstOrganization: {
__typename: 'CloudOrganizationConnection',
nodes: [{ __typename: 'CloudOrganization', id: '122' }],
},
organizations: {
__typename: 'CloudOrganizationConnection',
nodes: [{
__typename: 'CloudOrganization',
name: `Cypress Test Account`,
id: '122',
projects: {
nodes: [],
},
}],
},
}

result.currentProject = null
},
render: (gqlVal) => {
return <LoginConnectModalsContent gql={gqlVal} />
},
})
[undefined, 'testContent'].forEach((content) => {
it('shows "Create Project" state if project is not set up', () => {
const { openLoginConnectModal, setUserFlag, setProjectFlag } = useLoginConnectStore()

setUserFlag('isLoggedIn', true)
setUserFlag('isMemberOfOrganization', true)
setUserFlag('isOrganizationLoaded', true)
setProjectFlag('isConfigLoaded', true)
setProjectFlag('isProjectConnected', false)

cy.mountFragment(LoginConnectModalsContentFragmentDoc, {
onResult: (result) => {
result.cloudViewer = { ...CloudUserStubs.me,
firstOrganization: {
__typename: 'CloudOrganizationConnection',
nodes: [{ __typename: 'CloudOrganization', id: '122' }],
},
organizations: {
__typename: 'CloudOrganizationConnection',
nodes: [{
__typename: 'CloudOrganization',
name: `Cypress Test Account`,
id: '122',
projects: {
nodes: [],
},
}],
},
}

result.currentProject = null
},
render: (gqlVal) => {
return <LoginConnectModalsContent gql={gqlVal} />
},
})

const createProjectStub = cy.stub().as('createProjectStub')
const createProjectStub = cy.stub().as('createProjectStub')

cy.stubMutationResolver(SelectCloudProjectModal_CreateCloudProjectDocument, (defineResult, variables) => {
createProjectStub(variables)
cy.stubMutationResolver(SelectCloudProjectModal_CreateCloudProjectDocument, (defineResult, variables) => {
createProjectStub(variables)

return defineResult({} as any)
})
return defineResult({} as any)
})

cy.contains('Create project')
.should('not.exist')
.then(() => {
openLoginConnectModal({ utmMedium: 'testing' })
})
cy.contains('Create project')
.should('not.exist')
.then(() => {
openLoginConnectModal({ utmMedium: 'testing', utmContent: content })
})

cy.findAllByLabelText('Project name*(You can change this later)').type('test-project')

cy.contains('button', 'Create project')
.click()
.then(() => {
expect(createProjectStub.lastCall.args[0]).to.deep.eq({
name: 'test-project',
orgId: '122',
medium: 'testing',
source: 'Binary: Launchpad',
public: false,
campaign: 'Create project',
cohort: '',
cy.findAllByLabelText('Project name*(You can change this later)').type('test-project')

cy.contains('button', 'Create project')
.click()
.then(() => {
expect(createProjectStub.lastCall.args[0]).to.deep.eq({
name: 'test-project',
orgId: '122',
medium: 'testing',
source: 'Binary: Launchpad',
public: false,
campaign: 'Create project',
cohort: content || '',
})
})
})

cy.get('@createProjectStub').should('have.been.calledOnce')
cy.get('@createProjectStub').should('have.been.calledOnce')
})
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@
v-if="userStatusMatches('isLoggedOut') || keepLoginOpen"
:gql="gqlRef"
:utm-medium="loginConnectStore.utmMedium"
:utm-content="loginConnectStore.utmContent"
@cancel="closeLoginConnectModal"
@close="handleCloseLogin"
/>
<RecordRunModal
v-else-if="userStatusMatches('needsRecordedRun')"
:utm-medium="loginConnectStore.utmMedium"
:utm-content="loginConnectStore.utmContent"
@cancel="closeLoginConnectModal"
/>
<CloudConnectModals
v-else-if="userStatusMatches('needsProjectConnect') || userStatusMatches('needsOrgConnect')"
:show="loginConnectStore.user.isLoggedIn"
:gql="gqlRef"
:utm-medium="loginConnectStore.utmMedium"
:utm-content="loginConnectStore.utmContent"
@cancel="closeLoginConnectModal"
@success="closeLoginConnectModal"
/>
Expand Down
6 changes: 5 additions & 1 deletion packages/frontend-shared/src/store/login-connect-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface LoginConnectState {
hasInitiallyLoaded: boolean
isLoginConnectOpen: boolean
utmMedium: string
utmContent?: string
cypressFirstOpened?: number
user: {
isLoggedIn: boolean
Expand Down Expand Up @@ -54,6 +55,7 @@ export const useLoginConnectStore = defineStore({
return {
hasInitiallyLoaded: false,
utmMedium: '',
utmContent: undefined,
isLoginConnectOpen: false,
cypressFirstOpened: undefined,
userData: undefined,
Expand All @@ -80,13 +82,15 @@ export const useLoginConnectStore = defineStore({
setHasInitiallyLoaded () {
this.hasInitiallyLoaded = true
},
openLoginConnectModal ({ utmMedium }: { utmMedium: string }) {
openLoginConnectModal ({ utmMedium, utmContent }: { utmMedium: string, utmContent?: string }) {
this.isLoginConnectOpen = true
this.utmMedium = utmMedium
this.utmContent = utmContent
},
closeLoginConnectModal () {
this.isLoginConnectOpen = false
this.utmMedium = ''
this.utmContent = undefined
},
setUserFlag (name: keyof LoginConnectState['user'], newVal: boolean) {
this.user[name] = newVal
Expand Down

5 comments on commit 9c98b5e

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 9c98b5e Mar 10, 2023

Choose a reason for hiding this comment

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

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.8.0/linux-arm64/develop-9c98b5e08583764ef228d9b8a40e5f28e7f41ade/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 9c98b5e Mar 10, 2023

Choose a reason for hiding this comment

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

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.8.0/linux-x64/develop-9c98b5e08583764ef228d9b8a40e5f28e7f41ade/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 9c98b5e Mar 10, 2023

Choose a reason for hiding this comment

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

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.8.0/darwin-arm64/develop-9c98b5e08583764ef228d9b8a40e5f28e7f41ade/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 9c98b5e Mar 10, 2023

Choose a reason for hiding this comment

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

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.8.0/darwin-x64/develop-9c98b5e08583764ef228d9b8a40e5f28e7f41ade/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 9c98b5e Mar 10, 2023

Choose a reason for hiding this comment

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

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.8.0/win32-x64/develop-9c98b5e08583764ef228d9b8a40e5f28e7f41ade/cypress.tgz

Please sign in to comment.