Skip to content

Commit 640fce0

Browse files
update SyncButton to grab to param and append to login redirect
1 parent ce49513 commit 640fce0

File tree

2 files changed

+103
-73
lines changed

2 files changed

+103
-73
lines changed
+94-72
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,100 @@
11
import { act, render, screen } from '@testing-library/react'
2+
import qs from 'qs'
23
import { MemoryRouter, Route } from 'react-router-dom'
34

5+
import config from 'config'
6+
47
import { eventTracker } from 'services/events/events'
8+
import { Provider } from 'shared/api/helpers'
59

610
import SyncButton from './SyncButton'
711

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

10-
const wrapper: React.FC<React.PropsWithChildren> = ({ children }) => (
11-
<MemoryRouter initialEntries={['/sync']}>
12-
<Route path="/sync">{children}</Route>
13-
</MemoryRouter>
14-
)
15-
16-
describe('SyncButton', () => {
17-
describe('provider is set to gh', () => {
18-
it('renders sync button', () => {
19-
render(<SyncButton provider="gh" />, { wrapper })
20-
21-
const link = screen.getByRole('link', { name: /Sync with GitHub/ })
22-
23-
const expectedRedirect = encodeURIComponent('http://localhost:3000/gh')
24-
expect(link).toBeInTheDocument()
25-
expect(link).toHaveAttribute('href', `/login/gh?to=${expectedRedirect}`)
26-
})
27-
})
28-
29-
describe('provider is set to gl', () => {
30-
it('renders sync button', () => {
31-
render(<SyncButton provider="gl" />, { wrapper })
32-
33-
const link = screen.getByRole('link', { name: /Sync with GitLab/ })
34-
35-
const expectedRedirect = encodeURIComponent('http://localhost:3000/gl')
36-
expect(link).toBeInTheDocument()
37-
expect(link).toHaveAttribute('href', `/login/gl?to=${expectedRedirect}`)
38-
})
39-
})
40-
41-
describe('provider is set to bb', () => {
42-
it('renders sync button', () => {
43-
render(<SyncButton provider="bb" />, { wrapper })
44-
45-
const link = screen.getByRole('link', { name: /Sync with Bitbucket/ })
14+
vi.mock('config')
15+
config.API_URL = 'secret-api-url'
4616

47-
const expectedRedirect = encodeURIComponent('http://localhost:3000/bb')
48-
expect(link).toBeInTheDocument()
49-
expect(link).toHaveAttribute('href', `/login/bb?to=${expectedRedirect}`)
50-
})
17+
const { location } = window
18+
beforeEach(() => {
19+
Object.defineProperty(window, 'location', {
20+
value: { ...location, protocol: 'http:', host: 'secret-api-url' },
5121
})
22+
})
5223

53-
describe('provider is set to ghe', () => {
54-
it('renders sync button', () => {
55-
render(<SyncButton provider="ghe" />, { wrapper })
56-
57-
const link = screen.getByRole('link', {
58-
name: /Sync with GitHub Enterprise/,
59-
})
60-
61-
const expectedRedirect = encodeURIComponent('http://localhost:3000/ghe')
62-
expect(link).toBeInTheDocument()
63-
expect(link).toHaveAttribute('href', `/login/ghe?to=${expectedRedirect}`)
64-
})
65-
})
66-
67-
describe('provider is set to gle', () => {
68-
it('renders sync button', () => {
69-
render(<SyncButton provider="gle" />, { wrapper })
70-
71-
const link = screen.getByRole('link', {
72-
name: /Sync with GitLab Enterprise/,
73-
})
24+
afterEach(() => {
25+
Object.defineProperty(window, 'location', { value: location })
26+
})
7427

75-
const expectedRedirect = encodeURIComponent('http://localhost:3000/gle')
76-
expect(link).toBeInTheDocument()
77-
expect(link).toHaveAttribute('href', `/login/gle?to=${expectedRedirect}`)
78-
})
79-
})
28+
const wrapper =
29+
(initialEntries = '/sync'): React.FC<React.PropsWithChildren> =>
30+
({ children }) => (
31+
<MemoryRouter initialEntries={[initialEntries]}>
32+
<Route path="/sync">{children}</Route>
33+
</MemoryRouter>
34+
)
35+
36+
interface Case {
37+
provider: Provider
38+
name: string
39+
redirectTo: string
40+
}
41+
42+
const cases: Case[] = [
43+
{
44+
provider: 'gh',
45+
name: 'GitHub',
46+
redirectTo: 'http://secret-api-url/gh',
47+
},
48+
{
49+
provider: 'ghe',
50+
name: 'GitHub Enterprise',
51+
redirectTo: 'http://secret-api-url/ghe',
52+
},
53+
{
54+
provider: 'gl',
55+
name: 'GitLab',
56+
redirectTo: 'http://secret-api-url/gl',
57+
},
58+
{
59+
provider: 'gle',
60+
name: 'GitLab Enterprise',
61+
redirectTo: 'http://secret-api-url/gle',
62+
},
63+
{
64+
provider: 'bb',
65+
name: 'Bitbucket',
66+
redirectTo: 'http://secret-api-url/bb',
67+
},
68+
69+
{
70+
provider: 'bbs',
71+
name: 'Bitbucket Server',
72+
redirectTo: 'http://secret-api-url/bbs',
73+
},
74+
]
8075

81-
describe('provider is set to bbs', () => {
76+
describe('SyncButton', () => {
77+
describe.each(cases)('$name', ({ name, provider, redirectTo }) => {
8278
it('renders sync button', () => {
83-
render(<SyncButton provider="bbs" />, { wrapper })
79+
render(<SyncButton provider={provider} />, { wrapper: wrapper() })
8480

8581
const link = screen.getByRole('link', {
86-
name: /Sync with Bitbucket Server/,
82+
name: new RegExp(`Sync with ${name}`),
8783
})
8884

89-
const expectedRedirect = encodeURIComponent('http://localhost:3000/bbs')
85+
const queryString = qs.stringify(
86+
{ to: redirectTo },
87+
{ addQueryPrefix: true }
88+
)
89+
const expectedRedirect = `secret-api-url/login/${provider}${queryString}`
9090
expect(link).toBeInTheDocument()
91-
expect(link).toHaveAttribute('href', `/login/bbs?to=${expectedRedirect}`)
91+
expect(link).toHaveAttribute('href', expectedRedirect)
9292
})
9393
})
9494

9595
it('emits event on click', () => {
9696
console.error = () => {} // silence error about navigation on click
97-
render(<SyncButton provider="gh" />, { wrapper })
97+
render(<SyncButton provider="gh" />, { wrapper: wrapper() })
9898

9999
const link = screen.getByRole('link', { name: /Sync with GitHub/ })
100100

@@ -109,4 +109,26 @@ describe('SyncButton', () => {
109109
},
110110
})
111111
})
112+
113+
describe('when a to param is provided', () => {
114+
it('appends the to param to the redirect url', () => {
115+
render(<SyncButton provider="gh" />, {
116+
wrapper: wrapper('/sync?to=/test'),
117+
})
118+
119+
const redirectQueryString = qs.stringify(
120+
{ to: '/test' },
121+
{ addQueryPrefix: true }
122+
)
123+
const queryString = qs.stringify(
124+
{ to: `http://secret-api-url/gh${redirectQueryString}` },
125+
{ addQueryPrefix: true }
126+
)
127+
const link = screen.getByRole('link', { name: /Sync with GitHub/ })
128+
expect(link).toHaveAttribute(
129+
'href',
130+
`secret-api-url/login/gh${queryString}`
131+
)
132+
})
133+
})
112134
})

src/pages/SyncProviderPage/SyncButton.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import qs from 'qs'
2+
13
import { eventTracker } from 'services/events/events'
4+
import { useLocationParams } from 'services/navigation/useLocationParams'
25
import { useNavLinks } from 'services/navigation/useNavLinks'
36
import { Provider } from 'shared/api/helpers'
47
import { loginProviderImage } from 'shared/utils/loginProviders'
@@ -10,8 +13,13 @@ interface SyncButtonProps {
1013

1114
const SyncButton: React.FC<SyncButtonProps> = ({ provider }) => {
1215
const { signIn } = useNavLinks()
13-
const to = `${window.location.protocol}//${window.location.host}/${provider}`
16+
const { params } = useLocationParams()
17+
1418
const providerName = providerToName(provider)
19+
// @ts-expect-error useLocationParams needs to be typed
20+
const queryString = qs.stringify({ to: params?.to }, { addQueryPrefix: true })
21+
const to = `${window.location.protocol}//${window.location.host}/${provider}${queryString}`
22+
1523
return (
1624
<div className="flex h-14 items-center rounded-sm border border-ds-gray-quaternary bg-ds-gray-primary text-left shadow">
1725
<a

0 commit comments

Comments
 (0)