Skip to content

Commit 88878f0

Browse files
Merge branch 'main' into cy/light_dark_switch
2 parents a75c5f6 + b7ce614 commit 88878f0

File tree

37 files changed

+1590
-174
lines changed

37 files changed

+1590
-174
lines changed

src/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { Router } from 'react-router-dom'
1212
import { CompatRouter } from 'react-router-dom-v5-compat'
1313

1414
import ErrorBoundary from 'layouts/shared/ErrorBoundary'
15+
import { initEventTracker } from 'services/events/events'
1516
import { withFeatureFlagProvider } from 'shared/featureFlags'
1617

1718
import App from './App'
@@ -38,6 +39,7 @@ const history = createBrowserHistory()
3839

3940
const TOO_MANY_REQUESTS_ERROR_CODE = 429
4041

42+
initEventTracker()
4143
setupSentry({ history })
4244

4345
const queryClient = new QueryClient({

src/layouts/BaseLayout/BaseLayout.test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,22 @@ const mockNavigatorData = {
170170
},
171171
}
172172

173+
const mockOwnerContext = {
174+
owner: {
175+
ownerid: 123,
176+
},
177+
}
178+
179+
const mockRepoContext = {
180+
owner: {
181+
repository: {
182+
__typename: 'Repository',
183+
repoid: 321,
184+
private: false,
185+
},
186+
},
187+
}
188+
173189
const server = setupServer()
174190
const queryClient = new QueryClient({
175191
defaultOptions: {
@@ -288,6 +304,14 @@ describe('BaseLayout', () => {
288304
graphql.query('NavigatorData', () => {
289305
return HttpResponse.json({ data: mockNavigatorData })
290306
}),
307+
graphql.query('OwnerContext', () => {
308+
return HttpResponse.json({ data: mockOwnerContext })
309+
}),
310+
graphql.query('RepoContext', () => {
311+
return HttpResponse.json({
312+
data: mockRepoContext,
313+
})
314+
}),
291315
http.get('/internal/users/current', () => {
292316
return HttpResponse.json({})
293317
})

src/layouts/BaseLayout/BaseLayout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import NetworkErrorBoundary from 'layouts/shared/NetworkErrorBoundary'
1010
import SilentNetworkErrorWrapper from 'layouts/shared/SilentNetworkErrorWrapper'
1111
import ToastNotifications from 'layouts/ToastNotifications'
1212
import { RepoBreadcrumbProvider } from 'pages/RepoPage/context'
13+
import { useEventContext } from 'services/events/hooks'
1314
import { useImpersonate } from 'services/impersonate'
1415
import { useTracking } from 'services/tracking'
1516
import GlobalBanners from 'shared/GlobalBanners'
@@ -77,6 +78,7 @@ interface URLParams {
7778
function BaseLayout({ children }: React.PropsWithChildren) {
7879
const { provider, owner, repo } = useParams<URLParams>()
7980
useTracking()
81+
useEventContext()
8082
const { isImpersonating } = useImpersonate()
8183
const {
8284
isFullExperience,

src/layouts/Header/components/UserDropdown/UserDropdown.test.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { type Mock } from 'vitest'
88

99
import config from 'config'
1010

11+
import { eventTracker } from 'services/events/events'
1112
import { useImage } from 'services/image'
1213
import { Plans } from 'shared/utils/billing'
1314

@@ -60,6 +61,7 @@ const mockUser = {
6061
vi.mock('services/image')
6162
vi.mock('config')
6263
vi.mock('js-cookie')
64+
vi.mock('services/events/events')
6365

6466
const queryClient = new QueryClient({
6567
defaultOptions: { queries: { retry: false } },
@@ -214,6 +216,39 @@ describe('UserDropdown', () => {
214216
'https://github.com/apps/codecov/installations/new'
215217
)
216218
})
219+
220+
describe('when app access link is clicked', () => {
221+
it('tracks a Button Clicked event', async () => {
222+
const { user } = setup()
223+
render(<UserDropdown />, {
224+
wrapper: wrapper(),
225+
})
226+
227+
expect(
228+
screen.queryByText('Install Codecov app')
229+
).not.toBeInTheDocument()
230+
231+
const openSelect = await screen.findByTestId('user-dropdown-trigger')
232+
await user.click(openSelect)
233+
234+
const link = screen.getByText('Install Codecov app')
235+
expect(link).toBeVisible()
236+
expect(link).toHaveAttribute(
237+
'href',
238+
'https://github.com/apps/codecov/installations/new'
239+
)
240+
241+
await user.click(link)
242+
243+
expect(eventTracker().track).toHaveBeenCalledWith({
244+
type: 'Button Clicked',
245+
properties: {
246+
buttonName: 'Install GitHub App',
247+
buttonLocation: 'User dropdown',
248+
},
249+
})
250+
})
251+
})
217252
})
218253
})
219254
describe('when not on GitHub', () => {

src/layouts/Header/components/UserDropdown/UserDropdown.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useHistory, useParams } from 'react-router-dom'
22

33
import config from 'config'
44

5+
import { eventTracker } from 'services/events/events'
56
import { useUser } from 'services/user'
67
import { Provider } from 'shared/api/helpers'
78
import { providerToName } from 'shared/utils/provider'
@@ -42,6 +43,14 @@ function UserDropdown() {
4243
{
4344
to: { pageName: 'codecovAppInstallation' },
4445
children: 'Install Codecov app',
46+
onClick: () =>
47+
eventTracker().track({
48+
type: 'Button Clicked',
49+
properties: {
50+
buttonName: 'Install GitHub App',
51+
buttonLocation: 'User dropdown',
52+
},
53+
}),
4554
} as DropdownItem,
4655
]
4756
: []

src/pages/OwnerPage/HeaderBanners/GithubConfigBanner/GithubConfigBanner.jsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useParams } from 'react-router-dom'
22

3+
import { eventTracker } from 'services/events/events'
34
import { providerToName } from 'shared/utils/provider'
45
import A from 'ui/A'
56
import Banner from 'ui/Banner'
@@ -21,6 +22,15 @@ const GithubConfigBanner = () => {
2122
<A
2223
data-testid="codecovGithubApp-link"
2324
to={{ pageName: 'codecovGithubAppSelectTarget' }}
25+
onClick={() =>
26+
eventTracker().track({
27+
type: 'Button Clicked',
28+
properties: {
29+
buttonName: 'Install GitHub App',
30+
buttonLocation: 'Configure GitHub app banner',
31+
},
32+
})
33+
}
2434
>
2535
Codecov&apos;s GitHub app
2636
</A>

src/pages/OwnerPage/HeaderBanners/GithubConfigBanner/GithubConfigBanner.test.jsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
import { render, screen } from '@testing-library/react'
1+
import { act, render, screen } from '@testing-library/react'
22
import { MemoryRouter, Route, Switch } from 'react-router-dom'
33

4+
import { eventTracker } from 'services/events/events'
5+
46
import GithubConfigBanner from './GithubConfigBanner'
57

8+
vi.mock('services/events/events')
9+
610
const wrapper =
711
({ provider = 'gh' }) =>
812
({ children }) => {
@@ -34,6 +38,27 @@ describe('GithubConfigBanner', () => {
3438
)
3539
expect(body).toBeInTheDocument()
3640
})
41+
42+
describe('and button is clicked', () => {
43+
it('tracks a Button Clicked event', async () => {
44+
render(<GithubConfigBanner />, {
45+
wrapper: wrapper({ provider: 'gh' }),
46+
})
47+
48+
const title = screen.getByText(/Codecov's GitHub app/)
49+
expect(title).toBeInTheDocument()
50+
51+
act(() => title.click())
52+
53+
expect(eventTracker().track).toHaveBeenCalledWith({
54+
type: 'Button Clicked',
55+
properties: {
56+
buttonName: 'Install GitHub App',
57+
buttonLocation: 'Configure GitHub app banner',
58+
},
59+
})
60+
})
61+
})
3762
})
3863

3964
describe('when rendered with other providers', () => {

src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function BillingDetails() {
3030
<EmailAddress />
3131
<PaymentCard
3232
// @ts-expect-error - TODO fix this once we update PaymentCard to TS
33-
subscriptionDetail={subscriptionDetail}
33+
accountDetails={accountDetails}
3434
provider={provider}
3535
owner={owner}
3636
/>

src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import PropTypes from 'prop-types'
22
import { useState } from 'react'
33

4-
import { subscriptionDetailType } from 'services/account'
4+
import { accountDetailsPropType } from 'services/account'
55
import { formatTimestampToCalendarDate } from 'shared/utils/billing'
66
import A from 'ui/A'
77
import Button from 'ui/Button'
@@ -10,8 +10,9 @@ import Icon from 'ui/Icon'
1010
import BankInformation from './BankInformation'
1111
import CardInformation from './CardInformation'
1212
import PaymentMethodForm from './PaymentMethodForm'
13-
function PaymentCard({ subscriptionDetail, provider, owner }) {
13+
function PaymentCard({ accountDetails, provider, owner }) {
1414
const [isFormOpen, setIsFormOpen] = useState(false)
15+
const subscriptionDetail = accountDetails?.subscriptionDetail
1516
const card = subscriptionDetail?.defaultPaymentMethod?.card
1617
const usBankAccount = subscriptionDetail?.defaultPaymentMethod?.usBankAccount
1718

@@ -41,7 +42,7 @@ function PaymentCard({ subscriptionDetail, provider, owner }) {
4142
provider={provider}
4243
owner={owner}
4344
closeForm={() => setIsFormOpen(false)}
44-
subscriptionDetail={subscriptionDetail}
45+
accountDetails={accountDetails}
4546
/>
4647
) : card ? (
4748
<CardInformation card={card} subscriptionDetail={subscriptionDetail} />
@@ -72,7 +73,7 @@ function PaymentCard({ subscriptionDetail, provider, owner }) {
7273
}
7374

7475
PaymentCard.propTypes = {
75-
subscriptionDetail: subscriptionDetailType,
76+
accountDetails: accountDetailsPropType,
7677
provider: PropTypes.string.isRequired,
7778
owner: PropTypes.string.isRequired,
7879
}

0 commit comments

Comments
 (0)