Skip to content

Commit

Permalink
Fix coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
spalmurray-codecov committed Jan 17, 2025
1 parent c8902a9 commit 6144625
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 3 deletions.
24 changes: 24 additions & 0 deletions src/layouts/BaseLayout/BaseLayout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,22 @@ const mockNavigatorData = {
},
}

const mockOwnerContext = {
owner: {
ownerid: 123,
},
}

const mockRepoContext = {
owner: {
repository: {
__typename: 'Repository',
repoid: 321,
private: false,
},
},
}

const server = setupServer()
const queryClient = new QueryClient({
defaultOptions: {
Expand Down Expand Up @@ -288,6 +304,14 @@ describe('BaseLayout', () => {
graphql.query('NavigatorData', () => {
return HttpResponse.json({ data: mockNavigatorData })
}),
graphql.query('OwnerContext', () => {
return HttpResponse.json({ data: mockOwnerContext })
}),
graphql.query('RepoContext', () => {
return HttpResponse.json({
data: mockRepoContext,
})
}),
http.get('/internal/users/current', () => {
return HttpResponse.json({})
})
Expand Down
35 changes: 35 additions & 0 deletions src/layouts/Header/components/UserDropdown/UserDropdown.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { type Mock } from 'vitest'

import config from 'config'

import { eventTracker } from 'services/events/events'
import { useImage } from 'services/image'
import { Plans } from 'shared/utils/billing'

Expand Down Expand Up @@ -60,6 +61,7 @@ const mockUser = {
vi.mock('services/image')
vi.mock('config')
vi.mock('js-cookie')
vi.mock('services/events/events')

const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
Expand Down Expand Up @@ -214,6 +216,39 @@ describe('UserDropdown', () => {
'https://github.com/apps/codecov/installations/new'
)
})

describe('when app access link is clicked', () => {
it('tracks a Button Clicked event', async () => {
const { user } = setup()
render(<UserDropdown />, {
wrapper: wrapper(),
})

expect(
screen.queryByText('Install Codecov app')
).not.toBeInTheDocument()

const openSelect = await screen.findByTestId('user-dropdown-trigger')
await user.click(openSelect)

const link = screen.getByText('Install Codecov app')
expect(link).toBeVisible()
expect(link).toHaveAttribute(
'href',
'https://github.com/apps/codecov/installations/new'
)

await user.click(link)

expect(eventTracker().track).toHaveBeenCalledWith({
type: 'Button Clicked',
properties: {
buttonType: 'Install GitHub App',
buttonLocation: 'User dropdown',
},
})
})
})
})
})
describe('when not on GitHub', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { render, screen } from '@testing-library/react'
import { act, render, screen } from '@testing-library/react'
import { MemoryRouter, Route, Switch } from 'react-router-dom'

import { eventTracker } from 'services/events/events'

import GithubConfigBanner from './GithubConfigBanner'

vi.mock('services/events/events')

const wrapper =
({ provider = 'gh' }) =>
({ children }) => {
Expand Down Expand Up @@ -34,6 +38,27 @@ describe('GithubConfigBanner', () => {
)
expect(body).toBeInTheDocument()
})

describe('and button is clicked', () => {
it('tracks a Button Clicked event', async () => {
render(<GithubConfigBanner />, {
wrapper: wrapper({ provider: 'gh' }),
})

const title = screen.getByText(/Codecov's GitHub app/)
expect(title).toBeInTheDocument()

act(() => title.click())

expect(eventTracker().track).toHaveBeenCalledWith({
type: 'Button Clicked',
properties: {
buttonType: 'Install GitHub App',
buttonLocation: 'Configure GitHub app banner',
},
})
})
})
})

describe('when rendered with other providers', () => {
Expand Down
18 changes: 18 additions & 0 deletions src/services/events/__mocks__/events.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { EventTracker } from '../types'

//
// Use this mock by
// vi.mock('services/events/events')
// and
// expect(eventTracker().track).toHaveBeenCalledWith()
//

const MOCK_EVENT_TRACKER: EventTracker = {
identify: vi.fn(),
track: vi.fn(),
setContext: vi.fn(),
}

export function eventTracker() {
return MOCK_EVENT_TRACKER
}
46 changes: 46 additions & 0 deletions src/services/events/events.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import config from 'config'

import { eventTracker, initEventTracker, StubbedEventTracker } from './events'
import { EventTracker } from './types'

vi.mock('config')
const mockCaptureException = vi.hoisted(() => vi.fn())
Expand Down Expand Up @@ -38,6 +39,51 @@ describe('EventTracker', () => {
})
})

describe('abstract EventTracker', () => {
it('should throw errors if instantiated', () => {
// @ts-expect-error instantiating an abstract class
const tracker = new EventTracker()
try {
tracker.setContext({})
} catch (e) {
expect(e).toEqual(
new Error(
'EventTracker is abstract. Method setContext must be implemented.'
)
)
}

try {
tracker.identify({
userOwnerId: 1,
provider: 'gh',
})
} catch (e) {
expect(e).toEqual(
new Error(
'EventTracker is abstract. Method identify must be implemented.'
)
)
}

try {
tracker.track({
type: 'Button Clicked',
properties: {
buttonType: 'Install GitHub App',
buttonLocation: 'test',
},
})
} catch (e) {
expect(e).toEqual(
new Error(
'EventTracker is abstract. Method track must be implemented.'
)
)
}
})
})

describe('when initEventTracker is called', () => {
describe('and initAmplitude() throws an error', () => {
beforeEach(() => {
Expand Down
27 changes: 26 additions & 1 deletion src/services/events/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,26 @@ afterAll(() => {

interface SetupArgs {
badOwner?: boolean
nullOwnerid?: boolean
badRepo?: boolean
repoError?: 'NotFoundError' | 'OwnerNotActivatedError'
}

describe('useEventContext', () => {
function setup({ badOwner = false, badRepo = false, repoError }: SetupArgs) {
function setup({
badOwner = false,
nullOwnerid = false,
badRepo = false,
repoError,
}: SetupArgs) {
server.use(
graphql.query('OwnerContext', () => {
if (badOwner) {
return HttpResponse.json({ data: {} })
}
if (nullOwnerid) {
return HttpResponse.json({ data: { owner: { ownerid: null } } })
}
return HttpResponse.json({ data: mockOwnerContext })
}),
graphql.query('RepoContext', () => {
Expand Down Expand Up @@ -149,6 +158,22 @@ describe('useEventContext', () => {
})
})

describe('when called with null ownerid', () => {
it('sets event context with undefined ownerid', async () => {
setup({ nullOwnerid: true })
renderHook(() => useEventContext(), {
wrapper: ownerWrapper,
})

await waitFor(() => {
expect(mockedSetContext).toHaveBeenCalledWith({
owner: undefined,
repo: undefined,
})
})
})
})

describe('OwnerContext hook', () => {
describe('when bad data is returned', () => {
it('rejects with 404 failed to parse', async () => {
Expand Down
32 changes: 31 additions & 1 deletion src/shared/ListRepo/InactiveRepo/InactiveRepo.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen } from '@testing-library/react'
import { act, render, screen } from '@testing-library/react'
import React from 'react'
import { MemoryRouter, Route } from 'react-router-dom'

import { eventTracker } from 'services/events/events'

import InactiveRepo from './InactiveRepo'

const queryClient = new QueryClient()
Expand All @@ -14,6 +16,8 @@ const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
</QueryClientProvider>
)

vi.mock('services/events/events')

describe('InactiveRepo', () => {
it('renders "Deactivated" Text when not active', async () => {
render(<InactiveRepo isActive owner="bob" />, { wrapper })
Expand Down Expand Up @@ -44,4 +48,30 @@ describe('InactiveRepo', () => {
expect(ctaText).toBeInTheDocument()
expect(ctaText).toHaveAttribute('href', '/gh/bob/coolguy/new')
})

it('tracks a Button Clicked event when Configure is clicked', async () => {
render(
<InactiveRepo
isActive={false}
isCurrentUserPartOfOrg
repoName="coolguy"
owner="bob"
/>,
{ wrapper }
)

const ctaText = await screen.findByText(/Configure/)
expect(ctaText).toBeInTheDocument()
expect(ctaText).toHaveAttribute('href', '/gh/bob/coolguy/new')

act(() => ctaText.click())

expect(eventTracker().track).toHaveBeenCalledWith({
type: 'Button Clicked',
properties: {
buttonType: 'Configure Repo',
buttonLocation: 'Repo list',
},
})
})
})
62 changes: 62 additions & 0 deletions src/ui/ContextSwitcher/ContextSwitcher.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { MemoryRouter, Route, Switch } from 'react-router-dom'

import config, { DEFAULT_GH_APP } from 'config'

import { eventTracker } from 'services/events/events'
import { useImage } from 'services/image'

import ContextSwitcher from './ContextSwitcher'

vi.mock('services/events/events')
vi.mock('services/image')
const mocks = vi.hoisted(() => ({
useIntersection: vi.fn(),
Expand Down Expand Up @@ -713,6 +715,66 @@ describe('ContextSwitcher', () => {
})
})

describe('when install gh app button is clicked', () => {
it('tracks a Button Clicked event', async () => {
const { user } = setup()
render(
<ContextSwitcher
activeContext={{
username: 'laudna',
avatarUrl: 'http://127.0.0.1/avatar-url',
}}
contexts={[
{
owner: {
username: 'laudna',
avatarUrl: 'http://127.0.0.1/avatar-url',
},
pageName: 'provider',
},
{
owner: {
username: 'spotify',
avatarUrl: 'http://127.0.0.1/avatar-url',
},
pageName: 'owner',
},
{
owner: {
username: 'codecov',
avatarUrl: 'http://127.0.0.1/avatar-url',
},
pageName: 'owner',
},
]}
currentUser={{
defaultOrgUsername: 'codecov',
}}
src="imageUrl"
isLoading={false}
error={null}
/>,
{
wrapper: wrapper(),
}
)

const button = await screen.findByRole('button', { expanded: false })
await user.click(button)

const appButton = await screen.findByText('Install Codecov GitHub app')
await user.click(appButton)

expect(eventTracker().track).toHaveBeenCalledWith({
type: 'Button Clicked',
properties: {
buttonType: 'Install GitHub App',
buttonLocation: 'Org selector',
},
})
})
})

describe('when on self-hosted', () => {
beforeEach(() => {
config.IS_SELF_HOSTED = true
Expand Down

0 comments on commit 6144625

Please sign in to comment.