diff --git a/packages/app/src/debug/empty/DebugEmptyStates.cy.tsx b/packages/app/src/debug/empty/DebugEmptyStates.cy.tsx
index f07e42d1b02d..a48f1b91d8f8 100644
--- a/packages/app/src/debug/empty/DebugEmptyStates.cy.tsx
+++ b/packages/app/src/debug/empty/DebugEmptyStates.cy.tsx
@@ -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'
@@ -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(
+
+ {{
+ cta: slotVariableStub,
+ }}
+ ,
+ )
+
+ cy.get('@slot').should('be.calledWith', { utmContent: Cypress.sinon.match.string })
+ })
+ })
+
context('not logged in', () => {
it('renders', () => {
const loginConnectStore = useLoginConnectStore()
diff --git a/packages/app/src/debug/empty/DebugEmptyView.vue b/packages/app/src/debug/empty/DebugEmptyView.vue
index b169f3fd826b..bdea0970aebf 100644
--- a/packages/app/src/debug/empty/DebugEmptyView.vue
+++ b/packages/app/src/debug/empty/DebugEmptyView.vue
@@ -15,7 +15,10 @@
-
+
-
-
+
+
diff --git a/packages/app/src/debug/empty/DebugNotLoggedIn.vue b/packages/app/src/debug/empty/DebugNotLoggedIn.vue
index 3c93a88e6ad2..cd3810c0b043 100644
--- a/packages/app/src/debug/empty/DebugNotLoggedIn.vue
+++ b/packages/app/src/debug/empty/DebugNotLoggedIn.vue
@@ -7,8 +7,11 @@
:slideshow-campaign="DEBUG_SLIDESHOW.campaigns.login"
help-link-href="https://on.cypress.io/debug-page"
>
-
-
+
+
diff --git a/packages/app/src/debug/utils/constants.ts b/packages/app/src/debug/utils/constants.ts
index 5cbf8a446c2c..7ab6f734f36a 100644
--- a/packages/app/src/debug/utils/constants.ts
+++ b/packages/app/src/debug/utils/constants.ts
@@ -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
diff --git a/packages/app/src/runs/CloudConnectButton.cy.tsx b/packages/app/src/runs/CloudConnectButton.cy.tsx
index 05cb7a6cd106..35e9c5825ecb 100644
--- a/packages/app/src/runs/CloudConnectButton.cy.tsx
+++ b/packages/app/src/runs/CloudConnectButton.cy.tsx
@@ -31,7 +31,16 @@ describe('', { 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(() =>
)
+
+ cy.contains('button', 'Connect a Cypress Cloud project').click()
+
+ cy.get('@openLoginConnectModal').should('have.been.calledWith', { utmMedium: 'testing', utmContent: 'content' })
})
})
})
diff --git a/packages/app/src/runs/CloudConnectButton.vue b/packages/app/src/runs/CloudConnectButton.vue
index fba70554b6d0..255d8d389997 100644
--- a/packages/app/src/runs/CloudConnectButton.vue
+++ b/packages/app/src/runs/CloudConnectButton.vue
@@ -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') }}
@@ -24,6 +24,7 @@ const { t } = useI18n()
const props = defineProps<{
class?: string
utmMedium: string
+ utmContent?: string
}>()
diff --git a/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.cy.tsx b/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.cy.tsx
index ba64ce522afd..d828523e259b 100644
--- a/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.cy.tsx
+++ b/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.cy.tsx
@@ -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'
@@ -7,96 +7,118 @@ import { useLoginConnectStore } from '../store/login-connect-store'
describe('', () => {
context('when user is logged out', () => {
- it('shows login modal', () => {
- const { openLoginConnectModal } = useLoginConnectStore()
-
- cy.mountFragment(LoginConnectModalsContentFragmentDoc, {
- onResult: (result) => {
- result.cloudViewer = null
- },
- render: (gqlVal) => {
- return
- },
- })
+ [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
+ },
+ })
+
+ 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
- },
- })
+ [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
+ },
+ })
- 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')
+ })
})
})
})
diff --git a/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.vue b/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.vue
index f8bca76719ec..3626b8f4df96 100644
--- a/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.vue
+++ b/packages/frontend-shared/src/gql-components/LoginConnectModalsContent.vue
@@ -4,12 +4,14 @@
v-if="userStatusMatches('isLoggedOut') || keepLoginOpen"
:gql="gqlRef"
:utm-medium="loginConnectStore.utmMedium"
+ :utm-content="loginConnectStore.utmContent"
@cancel="closeLoginConnectModal"
@close="handleCloseLogin"
/>
diff --git a/packages/frontend-shared/src/store/login-connect-store.ts b/packages/frontend-shared/src/store/login-connect-store.ts
index 1ed3c0f3b5b9..91a1a7f904b7 100644
--- a/packages/frontend-shared/src/store/login-connect-store.ts
+++ b/packages/frontend-shared/src/store/login-connect-store.ts
@@ -10,6 +10,7 @@ export interface LoginConnectState {
hasInitiallyLoaded: boolean
isLoginConnectOpen: boolean
utmMedium: string
+ utmContent?: string
cypressFirstOpened?: number
user: {
isLoggedIn: boolean
@@ -54,6 +55,7 @@ export const useLoginConnectStore = defineStore({
return {
hasInitiallyLoaded: false,
utmMedium: '',
+ utmContent: undefined,
isLoginConnectOpen: false,
cypressFirstOpened: undefined,
userData: undefined,
@@ -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