Skip to content

Commit

Permalink
Merge branch 'develop' into zachw/fix-svelte-mount-log
Browse files Browse the repository at this point in the history
  • Loading branch information
ZachJW34 authored Sep 12, 2022
2 parents 97fbdfc + 405e7f7 commit 21f85fd
Show file tree
Hide file tree
Showing 63 changed files with 1,365 additions and 194 deletions.
3 changes: 2 additions & 1 deletion browser-versions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"chrome:beta": "105.0.5195.28",
"chrome:stable": "104.0.5112.101"
"chrome:stable": "104.0.5112.101",
"chrome:minimum": "64.0.3282.0"
}
30 changes: 25 additions & 5 deletions packages/app/cypress/e2e/runs.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,20 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
it('clicking the login button will open the login modal', () => {
cy.visitApp()
moveToRunsPage()
cy.contains('Log In').click()
cy.contains(defaultMessages.runs.connect.buttonUser).click()
cy.withCtx((ctx, o) => {
o.sinon.spy(ctx._apis.authApi, 'logIn')
})

cy.findByRole('dialog', { name: 'Log in to Cypress' }).within(() => {
cy.get('button').contains('Log In')
cy.contains('button', 'Log In').click()
})

cy.withCtx((ctx, o) => {
// validate utmSource
expect((ctx._apis.authApi.logIn as SinonStub).lastCall.args[1]).to.eq('Binary: App')
// validate utmMedium
expect((ctx._apis.authApi.logIn as SinonStub).lastCall.args[2]).to.eq('Runs Tab')
})
})

Expand Down Expand Up @@ -239,6 +250,7 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
moveToRunsPage()

cy.withCtx(async (ctx, options) => {
ctx.coreData.app.browserStatus = 'open'
options.sinon.stub(ctx._apis.electronApi, 'isMainWindowFocused').returns(false)
options.sinon.stub(ctx._apis.authApi, 'logIn').callsFake(async (onMessage) => {
setTimeout(() => {
Expand Down Expand Up @@ -272,8 +284,8 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
})

context('Runs - Create Project', () => {
it('when a project is created, injects new projectId into the config file', () => {
cy.remoteGraphQLIntercept(async (obj) => {
it('when a project is created, injects new projectId into the config file, and sends expected UTM params', () => {
cy.remoteGraphQLIntercept((obj) => {
if (obj.operationName === 'SelectCloudProjectModal_CreateCloudProject_cloudProjectCreate') {
obj.result.data!.cloudProjectCreate = {
slug: 'newProjectId',
Expand All @@ -290,7 +302,9 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
cy.loginUser()
cy.visitApp()

cy.withCtx(async (ctx) => {
cy.withCtx(async (ctx, o) => {
o.sinon.spy(ctx.cloud, 'executeRemoteGraphQL')

const config = await ctx.project.getConfig()

expect(config.projectId).to.not.equal('newProjectId')
Expand All @@ -305,6 +319,12 @@ describe('App: Runs', { viewportWidth: 1200 }, () => {
const config = await ctx.project.getConfig()

expect(config.projectId).to.equal('newProjectId')
expect(ctx.cloud.executeRemoteGraphQL).to.have.been.calledWithMatch({
fieldName: 'cloudProjectCreate',
operationVariables: {
medium: 'Runs Tab',
source: 'Binary: App',
} })
})
})

Expand Down
31 changes: 20 additions & 11 deletions packages/app/cypress/e2e/settings.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,12 @@ describe('App: Settings', () => {
cy.visitApp()
cy.get(SidebarSettingsLinkSelector).click()

cy.get('div[data-cy="app-header-bar"]').should('contain', 'Settings')
cy.contains('[data-cy="app-header-bar"]', 'Settings')
cy.contains('[data-cy="app-header-bar"] button', 'Log In').should('be.visible')

cy.findByText('Device Settings').should('be.visible')
cy.findByText('Project Settings').should('be.visible')
})

it('shows a button to log in if user is not connected', () => {
cy.startAppServer('e2e')
cy.visitApp()
cy.get(SidebarSettingsLinkSelector).click()
cy.findByText('Project Settings').click()
cy.get('button').contains('Log In')
cy.findByText('Dashboard Settings').should('be.visible')
})

describe('Cloud Settings', () => {
Expand Down Expand Up @@ -406,7 +401,7 @@ describe('App: Settings', () => {
})

describe('App: Settings without cloud', () => {
it('the projectId section shows a prompt to connect when there is no projectId', () => {
it('the projectId section shows a prompt to log in when there is no projectId, and uses correct UTM params', () => {
cy.scaffoldProject('simple-ct')
cy.openProject('simple-ct')
cy.startAppServer('component')
Expand All @@ -415,7 +410,21 @@ describe('App: Settings without cloud', () => {
cy.get(SidebarSettingsLinkSelector).click()
cy.findByText('Dashboard Settings').click()
cy.findByText('Project ID').should('exist')
cy.contains('button', 'Log in to the Cypress Dashboard').should('be.visible')
cy.withCtx((ctx, o) => {
o.sinon.spy(ctx._apis.authApi, 'logIn')
})

cy.contains('button', 'Log in to the Cypress Dashboard').click()
cy.findByRole('dialog', { name: 'Log in to Cypress' }).within(() => {
cy.contains('button', 'Log In').click()
})

cy.withCtx((ctx, o) => {
// validate utmSource
expect((ctx._apis.authApi.logIn as SinonStub).lastCall.args[1]).to.eq('Binary: App')
// validate utmMedium
expect((ctx._apis.authApi.logIn as SinonStub).lastCall.args[2]).to.eq('Settings Tab')
})
})

it('have returned browsers', () => {
Expand Down
8 changes: 8 additions & 0 deletions packages/app/cypress/e2e/specs_list_e2e.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ describe('App: Spec List (E2E)', () => {
cy.get('button').contains('23 Matches')
})

it('normalizes directory path separators for Windows', function () {
// On Windows, when a user types `e2e/accounts`, it should match `e2e\accounts`
clearSearchAndType('e2e/accounts')
cy.findAllByTestId('spec-item').should('have.length', 2)

cy.findByText('No specs matched your search:').should('not.be.visible')
})

// TODO: fix flaky test https://github.com/cypress-io/cypress/issues/23305
it.skip('saves the filter when navigating to a spec and back', function () {
const targetSpecFile = 'accounts_list.spec.js'
Expand Down
50 changes: 43 additions & 7 deletions packages/app/cypress/e2e/specs_list_latest_runs.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,37 @@ function averageDurationSelector (specFileName: string) {
return `${specRowSelector(specFileName)} [data-cy="average-duration"]`
}

function makeTestingCloudLink (status: string) {
return `https://google.com?utm_medium=Specs+Latest+Runs+Dots&utm_campaign=${status.toUpperCase()}&utm_source=Binary%3A+App`
}

function assertCorrectRunsLink (specFileName: string, status: string) {
// we avoid the full `cy.validateExternalLink` here because that command
// clicks the link, which focuses the link causing tooltips to appear,
// which produces problems elsewhere testing tooltip behavior
cy.findByRole('link', { name: specFileName })
.should('have.attr', 'href', makeTestingCloudLink(status))
.should('have.attr', 'data-cy', 'external') // to confirm the ExternalLink component is used
}

function validateTooltip (status: string) {
cy.validateExternalLink({
// TODO: (#23778) This name is so long because the entire tooltip is wrapped in a link,
// we can make this more accessible by having the name of the link describe the destination
// (which is currently not described) and keeping the other content separate.
name: `accounts_new.spec.js ${status} 4 months ago 2:23 - 2:39 skipped pending passed failed`,
// the main thing about testing this link is that is gets composed with the expected UTM params
href: makeTestingCloudLink(status),
})
.should('contain.text', 'accounts_new.spec.js')
.and('contain.text', '4 months ago')
.and('contain.text', '2:23 - 2:39')
.and('contain.text', 'skipped 0')
.and('contain.text', 'pending 1-2')
.and('contain.text', `passed 22-23`)
.and('contain.text', 'failed 1-2')
}

function specShouldShow (specFileName: string, runDotsClasses: string[], latestRunStatus: CloudRunStatus|'PLACEHOLDER') {
const latestStatusSpinning = latestRunStatus === 'RUNNING'

Expand All @@ -31,10 +62,11 @@ function specShouldShow (specFileName: string, runDotsClasses: string[], latestR
.should(`${latestStatusSpinning ? '' : 'not.'}have.class`, 'animate-spin')
.and('have.attr', 'data-cy-run-status', latestRunStatus)

// TODO: add link verification
// if (latestRunStatus !== 'PLACEHOLDER') {
// cy.get(`${specRowSelector(specFileName)} [data-cy="run-status-dots"]`).validateExternalLink('https://google.com')
// }
if (runDotsClasses?.length) {
assertCorrectRunsLink(`${specFileName} test results`, latestRunStatus)
} else {
cy.findByRole('link', { name: `${specFileName} test results` }).should('not.exist')
}
}

function simulateRunData () {
Expand Down Expand Up @@ -330,7 +362,9 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
specShouldShow('accounts_new.spec.js', ['gray-300', 'gray-300', 'jade-400'], 'RUNNING')
cy.get(dotSelector('accounts_new.spec.js', 'latest')).trigger('mouseenter')
cy.get('.v-popper__popper--shown').should('exist')
// TODO: verify the contents of the tooltip

validateTooltip('Running')

cy.get(dotSelector('accounts_new.spec.js', 'latest')).trigger('mouseleave')
cy.get(averageDurationSelector('accounts_new.spec.js')).contains('2:03')
})
Expand Down Expand Up @@ -601,7 +635,8 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
specShouldShow('accounts_list.spec.js', ['orange-400', 'gray-300', 'red-400'], 'PASSED')
cy.get(dotSelector('accounts_new.spec.js', 'latest')).trigger('mouseenter')
cy.get('.v-popper__popper--shown').should('exist')
// TODO: verify the contents of the tooltip

validateTooltip('Passed')
cy.get(dotSelector('accounts_new.spec.js', 'latest')).trigger('mouseleave')
cy.get(averageDurationSelector('accounts_list.spec.js')).contains('0:12')

Expand All @@ -611,7 +646,8 @@ describe('App/Cloud Integration - Latest runs and Average duration', { viewportW
specShouldShow('accounts_list.spec.js', ['orange-400', 'gray-300', 'red-400'], 'PASSED')
cy.get(dotSelector('accounts_new.spec.js', 'latest')).trigger('mouseenter')
cy.get('.v-popper__popper--shown').should('exist')
// TODO: verify the contents of the tooltip

validateTooltip('Passed')
cy.get(dotSelector('accounts_new.spec.js', 'latest')).trigger('mouseleave')
cy.get(averageDurationSelector('accounts_list.spec.js')).contains('0:12')
})
Expand Down
8 changes: 8 additions & 0 deletions packages/app/cypress/e2e/top-nav.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ describe('App Top Nav Workflows', () => {

const mockLogInActionsForUser = (user) => {
cy.withCtx(async (ctx, options) => {
ctx.coreData.app.browserStatus = 'open'
options.sinon.stub(ctx._apis.electronApi, 'isMainWindowFocused').returns(false)
options.sinon.stub(ctx._apis.authApi, 'logIn').callsFake(async (onMessage) => {
setTimeout(() => {
Expand Down Expand Up @@ -455,6 +456,13 @@ describe('App Top Nav Workflows', () => {

mockLogInActionsForUser(mockUser)
logIn({ expectedNextStepText: 'Connect project', displayName: mockUser.name })
cy.withCtx((ctx, o) => {
// validate utmSource
expect((ctx._apis.authApi.logIn as SinonStub).lastCall.args[1]).to.eq('Binary: App')
// validate utmMedium
expect((ctx._apis.authApi.logIn as SinonStub).lastCall.args[2]).to.eq('Nav')
})

cy.findByRole('dialog', { name: 'Create project' }).should('be.visible')
})
})
Expand Down
1 change: 1 addition & 0 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@types/faker": "5.5.8",
"@urql/core": "2.4.4",
"@urql/vue": "0.6.2",
"@vitejs/plugin-legacy": "^2.1.0",
"@vitejs/plugin-vue": "2.2.4",
"@vitejs/plugin-vue-jsx": "1.3.8",
"@vueuse/core": "7.2.2",
Expand Down
3 changes: 3 additions & 0 deletions packages/app/src/layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@
<component :is="Component" />
</transition>
</router-view>
<!-- "Nav" is the correct UTM medium below because
this is only opened by event emitted from the header bar-->
<CloudConnectModals
v-if="showConnectDialog && cloudModalQuery.data.value"
:show="showConnectDialog"
:gql="cloudModalQuery.data.value"
utm-medium="Nav"
@cancel="showConnectDialog = false"
@success="showConnectDialog = false"
/>
Expand Down
28 changes: 14 additions & 14 deletions packages/app/src/runner/event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,27 +181,27 @@ export class EventManager {
})
})

const logCommand = (logId) => {
const consoleProps = Cypress.runner.getConsolePropsForLogById(logId)
const logCommand = (testId, logId) => {
const consoleProps = Cypress.runner.getConsolePropsForLog(testId, logId)

logger.logFormatted(consoleProps)
}

this.reporterBus.on('runner:console:error', ({ err, commandId }) => {
this.reporterBus.on('runner:console:error', ({ err, testId, logId }) => {
if (!Cypress) return

if (commandId || err) logger.clearLog()
if (logId || err) logger.clearLog()

if (commandId) logCommand(commandId)
if (logId) logCommand(testId, logId)

if (err) logger.logError(err.stack)
})

this.reporterBus.on('runner:console:log', (logId) => {
this.reporterBus.on('runner:console:log', (testId, logId) => {
if (!Cypress) return

logger.clearLog()
logCommand(logId)
logCommand(testId, logId)
})

this.reporterBus.on('set:user:editor', (editor) => {
Expand All @@ -210,24 +210,24 @@ export class EventManager {

this.reporterBus.on('runner:restart', rerun)

const sendEventIfSnapshotProps = (logId, event) => {
const sendEventIfSnapshotProps = (testId, logId, event) => {
if (!Cypress) return

const snapshotProps = Cypress.runner.getSnapshotPropsForLogById(logId)
const snapshotProps = Cypress.runner.getSnapshotPropsForLog(testId, logId)

if (snapshotProps) {
this.localBus.emit(event, snapshotProps)
}
}

this.reporterBus.on('runner:show:snapshot', (logId) => {
sendEventIfSnapshotProps(logId, 'show:snapshot')
this.reporterBus.on('runner:show:snapshot', (testId, logId) => {
sendEventIfSnapshotProps(testId, logId, 'show:snapshot')
})

this.reporterBus.on('runner:hide:snapshot', this._hideSnapshot.bind(this))

this.reporterBus.on('runner:pin:snapshot', (logId) => {
sendEventIfSnapshotProps(logId, 'pin:snapshot')
this.reporterBus.on('runner:pin:snapshot', (testId, logId) => {
sendEventIfSnapshotProps(testId, logId, 'pin:snapshot')
})

this.reporterBus.on('runner:unpin:snapshot', this._unpinSnapshot.bind(this))
Expand Down Expand Up @@ -884,7 +884,7 @@ export class EventManager {
this.localBus.emit('save:app:state', state)
}

// usefulf for testing
// useful for testing
_testingOnlySetCypress (cypress: any) {
Cypress = cypress
}
Expand Down
6 changes: 3 additions & 3 deletions packages/app/src/runs/CloudConnectButton.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe('<CloudConnectButton />', () => {
result.cloudViewer = null
},
render (gqlVal) {
return <div class="h-screen"><CloudConnectButton gql={gqlVal} /></div>
return <div class="h-screen"><CloudConnectButton utmMedium="testing" gql={gqlVal} /></div>
},
})

Expand Down Expand Up @@ -56,7 +56,7 @@ describe('<CloudConnectButton />', () => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
return <div class="h-screen"><CloudConnectButton gql={gqlVal} /></div>
return <div class="h-screen"><CloudConnectButton utmMedium="testing" gql={gqlVal} /></div>
},
})

Expand All @@ -69,7 +69,7 @@ describe('<CloudConnectButton />', () => {
result.cloudViewer = cloudViewer
},
render (gqlVal) {
return <div class="h-screen"><CloudConnectButton gql={gqlVal} /></div>
return <div class="h-screen"><CloudConnectButton utmMedium="testing" gql={gqlVal} /></div>
},
})

Expand Down
4 changes: 3 additions & 1 deletion packages/app/src/runs/CloudConnectButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
<LoginModal
v-model="isLoginOpen"
:gql="props.gql"
utm-medium="Runs Tab"
:utm-medium="props.utmMedium"
:show-connect-button-after-login="!cloudProjectId"
@connect-project="isProjectConnectOpen = true"
/>
<CloudConnectModals
v-if="isProjectConnectOpen"
:show="isProjectConnectOpen"
:gql="props.gql"
:utm-medium="props.utmMedium"
@cancel="isProjectConnectOpen = false"
@success="isProjectConnectOpen = false; emit('success')"
/>
Expand Down Expand Up @@ -54,6 +55,7 @@ const emit = defineEmits<{
const props = defineProps<{
gql: CloudConnectButtonFragment
class?: string
utmMedium: string
}>()
const isLoginOpen = ref(false)
Expand Down
Loading

0 comments on commit 21f85fd

Please sign in to comment.