Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ All notable changes to Sourcegraph are documented in this file.
- Structural search now supports searching unindexed revisions. [#17967](https://github.com/sourcegraph/sourcegraph/pull/17967)
- New site config option `"allowSignup"` for SAML authentication to determine if automatically create new users is allowed. [#17989](https://github.com/sourcegraph/sourcegraph/pull/17989)
- Experimental: The webapp can now stream search results to the client, improving search performance. To enable it, add `{ "experimentalFeatures": { "searchStreaming": true } }` in user settings. [#16097](https://github.com/sourcegraph/sourcegraph/pull/16097)
- New product research sign-up page. This can be accessed by all users in their user settings. [#17945](https://github.com/sourcegraph/sourcegraph/pull/17945)
- New site config option `productResearchPage.enabled` to disable access to the product research sign-up page. [#17945](https://github.com/sourcegraph/sourcegraph/pull/17945)

### Changed

Expand Down
8 changes: 4 additions & 4 deletions client/browser/src/shared/code-hosts/shared/codeHost.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ describe('codeHost', () => {
type: 'CodeEditor',
},
])
expect(codeView.classList.contains('sg-mounted')).toBe(true)
expect(codeView).toHaveClass('sg-mounted')
const toolbar = elementRenderedAtMount(toolbarMount)
expect(toolbar).not.toBeUndefined()
})
Expand Down Expand Up @@ -347,7 +347,7 @@ describe('codeHost', () => {
])
await decorated()
expect(line.querySelectorAll('.line-decoration-attachment')).toHaveLength(1)
expect(line.querySelector('.line-decoration-attachment')!.textContent).toEqual('test decoration')
expect(line.querySelector('.line-decoration-attachment')!).toHaveTextContent('test decoration')

// Decorate the code view again, and verify that previous decorations
// are cleaned up and replaced by the new decorations.
Expand All @@ -372,7 +372,7 @@ describe('codeHost', () => {
)
.toPromise()
expect(line.querySelectorAll('.line-decoration-attachment').length).toBe(1)
expect(line.querySelector('.line-decoration-attachment')!.textContent).toEqual('test decoration 2')
expect(line.querySelector('.line-decoration-attachment')!).toHaveTextContent('test decoration 2')
})

it('decorates a diff code view', async () => {
Expand Down Expand Up @@ -785,7 +785,7 @@ describe('codeHost', () => {
expect(services.viewer.viewers.size).toEqual(1)
codeView.dispatchEvent(new MouseEvent('mouseover'))
sinon.assert.called(dom.getCodeElementFromTarget)
expect(nativeTooltip.classList.contains('native-tooltip--hidden')).toBe(true)
expect(nativeTooltip).toHaveClass('native-tooltip--hidden')
})

test('gracefully handles viewing private repos on a public Sourcegraph instance', async () => {
Expand Down
6 changes: 3 additions & 3 deletions client/shared/src/components/CodeExcerpt.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ describe('CodeExcerpt', () => {

it('renders the code portion of each row', () => {
const { container } = render(<CodeExcerpt {...defaultProps} />)
expect(getByText(container, 'first of code')).toBeTruthy()
expect(getByText(container, 'second of code')).toBeTruthy()
expect(getByText(container, 'third of code')).toBeTruthy()
expect(getByText(container, 'first of code')).toBeVisible()
expect(getByText(container, 'second of code')).toBeVisible()
expect(getByText(container, 'third of code')).toBeVisible()
})

it('highlights matches correctly', () => {
Expand Down
2 changes: 1 addition & 1 deletion client/shared/src/components/FileMatch.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('FileMatch', () => {

it('renders one result container', () => {
const { container } = render(<FileMatch {...defaultProps} />)
expect(getByTestId(container, 'result-container')).toBeTruthy()
expect(getByTestId(container, 'result-container')).toBeVisible()
expect(getAllByTestId(container, 'result-container').length).toBe(1)
})
})
2 changes: 1 addition & 1 deletion client/shared/src/components/FileMatchChildren.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ describe('FileMatchChildren', () => {
it('calls onSelect callback when an item is clicked', () => {
const { container } = render(<FileMatchChildren {...defaultProps} onSelect={onSelect} />)
const item = container.querySelector('.file-match-children__item')
expect(item).toBeTruthy()
expect(item).toBeVisible()
fireEvent.click(item!)
expect(onSelect.calledOnce).toBe(true)
})
Expand Down
12 changes: 6 additions & 6 deletions client/shared/src/components/ResultContainer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ describe('ResultContainer', () => {
expect(expandedItems.length).toBe(1)

const header = container.querySelector('.result-container__header--collapsible')
expect(header).toBeTruthy()
expect(header).toBeVisible()

fireEvent.click(header!)

Expand All @@ -122,19 +122,19 @@ describe('ResultContainer', () => {
it('displays the expand label when collapsed', () => {
const { container } = render(<ResultContainer {...defaultProps} />)
const header = getByTestId(container, 'result-container-header')
expect(header).toBeTruthy()
expect(getByText(container, 'Show matches')).toBeTruthy()
expect(header).toBeVisible()
expect(getByText(container, 'Show matches')).toBeVisible()
})

it('displays the collapse label when expanded', () => {
const { container } = render(<ResultContainer {...defaultProps} />)

const clickableHeader = container.querySelector('.result-container__header--collapsible')
expect(clickableHeader).toBeTruthy()
expect(clickableHeader).toBeVisible()

fireEvent.click(clickableHeader!)

expect(getByText(container, 'Hide matches')).toBeTruthy()
expect(getByText(container, 'Hide matches')).toBeVisible()
})

it('displays all results by default, when allExpanded is true', () => {
Expand All @@ -151,7 +151,7 @@ describe('ResultContainer', () => {
expect(expandedItems.length).toBe(5)

const header = container.querySelector('.result-container__header--collapsible')
expect(header).toBeTruthy()
expect(header).toBeVisible()
fireEvent.click(header!)

expandedItems = container.querySelectorAll('.file-match-children__item')
Expand Down
1 change: 1 addition & 0 deletions client/web/src/integration/jscontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const createJsContext = ({ sourcegraphBaseUrl }: { sourcegraphBaseUrl: st
campaignsEnabled: true,
codeIntelAutoIndexingEnabled: true,
externalServicesUserModeEnabled: false,
productResearchPageEnabled: true,
csrfToken: 'test-csrf-token',
assetsRoot: new URL('/.assets', sourcegraphBaseUrl).href,
deployType: 'dev',
Expand Down
3 changes: 3 additions & 0 deletions client/web/src/jscontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ export interface SourcegraphContext extends Pick<Required<SiteConfiguration>, 'e
brandName: string
}

/** Whether the product research sign-up page is enabled on the site. */
productResearchPageEnabled: boolean

/** The publishable key for the billing service (Stripe). */
billingPublishableKey?: string
}
Expand Down
10 changes: 5 additions & 5 deletions client/web/src/search/input/SearchPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,14 @@ describe('SearchPage', () => {
it('should not show home panels if on Sourcegraph.com and showEnterpriseHomePanels disabled', () => {
container = render(<SearchPage {...defaultProps} isSourcegraphDotCom={true} />).container
const homePanels = container.querySelector('.home-panels')
expect(homePanels).toBeFalsy()
expect(homePanels).not.toBeInTheDocument()
})

it('should show home panels if on Sourcegraph.com and showEnterpriseHomePanels enabled', () => {
container = render(<SearchPage {...defaultProps} isSourcegraphDotCom={true} showEnterpriseHomePanels={true} />)
.container
const homePanels = container.querySelector('.home-panels')
expect(homePanels).toBeTruthy()
expect(homePanels).toBeVisible()
})

it('should show home panels if on Sourcegraph.com and showEnterpriseHomePanels enabled with user logged out', () => {
Expand All @@ -82,18 +82,18 @@ describe('SearchPage', () => {
/>
).container
const homePanels = container.querySelector('.home-panels')
expect(homePanels).toBeFalsy()
expect(homePanels).not.toBeInTheDocument()
})

it('should not show home panels if showEnterpriseHomePanels disabled', () => {
container = render(<SearchPage {...defaultProps} />).container
const homePanels = container.querySelector('.home-panels')
expect(homePanels).toBeFalsy()
expect(homePanels).not.toBeInTheDocument()
})

it('should show home panels if showEnterpriseHomePanels enabled and not on Sourcegraph.com', () => {
container = render(<SearchPage {...defaultProps} showEnterpriseHomePanels={true} />).container
const homePanels = container.querySelector('.home-panels')
expect(homePanels).toBeTruthy()
expect(homePanels).toBeVisible()
})
})
24 changes: 12 additions & 12 deletions client/web/src/search/queryBuilder/QueryBuilder.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,38 +65,38 @@ describe('QueryBuilder', () => {
})

it('checks that the "Author", "Before", "After", and "Message" fields do not exist if the search type is set to code search', () => {
expect(queryByTestId(container, 'test-author')).toBeNull()
expect(queryByTestId(container, 'test-after')).toBeNull()
expect(queryByTestId(container, 'test-before')).toBeNull()
expect(queryByTestId(container, 'test-message')).toBeNull()
expect(queryByTestId(container, 'test-author')).not.toBeInTheDocument()
expect(queryByTestId(container, 'test-after')).not.toBeInTheDocument()
expect(queryByTestId(container, 'test-before')).not.toBeInTheDocument()
expect(queryByTestId(container, 'test-message')).not.toBeInTheDocument()
})

it('checks that the "Author", "Before", "After", and "Message" fields exist if the search type is set to diff search', async () => {
const typeField = getByDisplayValue(container, 'Code (default)')
fireEvent.change(typeField, { target: { value: 'diff' } })

await waitFor(() => queryByTestId(container, 'test-author'))
expect(queryByTestId(container, 'test-author')).toBeTruthy()
expect(queryByTestId(container, 'test-author')).toBeVisible()
await waitFor(() => queryByTestId(container, 'test-after'))
expect(queryByTestId(container, 'test-after')).toBeTruthy()
expect(queryByTestId(container, 'test-after')).toBeVisible()
await waitFor(() => queryByTestId(container, 'test-before'))
expect(queryByTestId(container, 'test-before')).toBeTruthy()
expect(queryByTestId(container, 'test-before')).toBeVisible()
await waitFor(() => queryByTestId(container, 'test-message'))
expect(queryByTestId(container, 'test-message')).toBeTruthy()
expect(queryByTestId(container, 'test-message')).toBeVisible()
})

it('checks that the "Author", "Before", and "After" fields exist if type is commit', async () => {
const typeField = getByDisplayValue(container, 'Code (default)')
fireEvent.change(typeField, { target: { value: 'commit' } })

await waitFor(() => queryByTestId(container, 'test-author'))
expect(queryByTestId(container, 'test-author')).toBeTruthy()
expect(queryByTestId(container, 'test-author')).toBeVisible()
await waitFor(() => queryByTestId(container, 'test-after'))
expect(queryByTestId(container, 'test-after')).toBeTruthy()
expect(queryByTestId(container, 'test-after')).toBeVisible()
await waitFor(() => queryByTestId(container, 'test-before'))
expect(queryByTestId(container, 'test-before')).toBeTruthy()
expect(queryByTestId(container, 'test-before')).toBeVisible()
await waitFor(() => queryByTestId(container, 'test-message'))
expect(queryByTestId(container, 'test-message')).toBeTruthy()
expect(queryByTestId(container, 'test-message')).toBeVisible()
})

it('fires the onFieldsQueryChange prop handler with the "author:" filter when updating the "Author" field', async () => {
Expand Down
22 changes: 11 additions & 11 deletions client/web/src/search/results/SearchResultsList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ describe('SearchResultsList', () => {
</BrowserRouter>
)

expect(queryByTestId(container, 'loading-container')).toBeTruthy()
expect(queryByTestId(container, 'loading-container')).toBeVisible()
})

it('shows error message when the search GraphQL request returns an error', () => {
Expand All @@ -141,7 +141,7 @@ describe('SearchResultsList', () => {
<SearchResultsList {...defaultProps} resultsOrError={{ message: 'test error', name: 'TestError' }} />
</BrowserRouter>
)
expect(getByTestId(container, 'search-results-list-error')).toBeTruthy()
expect(getByTestId(container, 'search-results-list-error')).toBeVisible()
})

it('renders the search results info bar when there are results', () => {
Expand All @@ -150,7 +150,7 @@ describe('SearchResultsList', () => {
<SearchResultsList {...defaultProps} />
</BrowserRouter>
)
expect(getByTestId(container, 'results-info-bar')).toBeTruthy()
expect(getByTestId(container, 'results-info-bar')).toBeVisible()
})

it('renders one search result', () => {
Expand All @@ -159,7 +159,7 @@ describe('SearchResultsList', () => {
<SearchResultsList {...defaultProps} />
</BrowserRouter>
)
expect(getByTestId(container, 'result-container')).toBeTruthy()
expect(getByTestId(container, 'result-container')).toBeVisible()
expect(getAllByTestId(container, 'result-container').length).toBe(1)
})

Expand All @@ -169,8 +169,8 @@ describe('SearchResultsList', () => {
<SearchResultsList {...defaultProps} />
</BrowserRouter>
)
expect(queryByTestId(container, 'loading-container')).toBeFalsy()
expect(queryByTestId(container, 'search-results-list-error')).toBeFalsy()
expect(queryByTestId(container, 'loading-container')).not.toBeInTheDocument()
expect(queryByTestId(container, 'search-results-list-error')).not.toBeInTheDocument()
})

it('renders correct number of search results if there are multiple', () => {
Expand Down Expand Up @@ -199,7 +199,7 @@ describe('SearchResultsList', () => {
<SearchResultsList {...props} />
</BrowserRouter>
)
expect(getByTestId(container, 'search-show-more-button')).toBeTruthy()
expect(getByTestId(container, 'search-show-more-button')).toBeVisible()
})

it('does not display "Show More" if the limit isn\'t hit', () => {
Expand Down Expand Up @@ -265,7 +265,7 @@ describe('SearchResultsList', () => {
</BrowserRouter>
)
scrollToBottom()
expect(getByTestId(container, 'search-show-more-button')).toBeTruthy()
expect(getByTestId(container, 'search-show-more-button')).toBeVisible()
})

it('does not add filters to query in search suggestions link', () => {
Expand Down Expand Up @@ -295,7 +295,7 @@ describe('SearchResultsList', () => {
)

const link = getByTestId(container, 'proposed-query-link') as HTMLAnchorElement
expect(link).toBeTruthy()
expect(link).toBeVisible()
expect(link.href).toStrictEqual('http://localhost/search?q=repo:test1%7Ctest2&patternType=regexp')
})

Expand Down Expand Up @@ -328,8 +328,8 @@ describe('SearchResultsList', () => {
const link = getByTestId(container, 'proposed-query-link') as HTMLAnchorElement
const result = getByTestId(container, 'result-container')

expect(link).toBeTruthy()
expect(result).toBeTruthy()
expect(link).toBeVisible()
expect(result).toBeVisible()
expect(link.compareDocumentPosition(result)).toStrictEqual(link.DOCUMENT_POSITION_FOLLOWING)
})
})
27 changes: 27 additions & 0 deletions client/web/src/user/settings/research/ProductResearch.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import { render, RenderResult } from '@testing-library/react'
import { ProductResearchPage } from './ProductResearch'
import { NOOP_TELEMETRY_SERVICE } from '../../../../../shared/src/telemetry/telemetryService'

describe('ProductResearchPage', () => {
let queries: RenderResult

beforeEach(() => {
queries = render(
<ProductResearchPage
telemetryService={NOOP_TELEMETRY_SERVICE}
authenticatedUser={{ email: 'test@sourcegraph.com' }}
/>
)
})

test('Renders page correctly', () => {
expect(queries.getByText('Product research and feedback')).toBeVisible()
})

test('renders sign up now link correctly', () => {
expect(queries.getByText('Sign up now').closest('a')?.href).toMatchInlineSnapshot(
'"https://share.hsforms.com/1tkScUc65Tm-Yu98zUZcLGw1n7ku?email=test%40sourcegraph.com"'
)
})
})
33 changes: 33 additions & 0 deletions client/web/src/user/settings/research/ProductResearch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { useEffect } from 'react'
import OpenInNewIcon from 'mdi-react/OpenInNewIcon'
import { TelemetryService } from '../../../../../shared/src/telemetry/telemetryService'
import { AuthenticatedUser } from '../../../auth'

interface Props {
telemetryService: TelemetryService
authenticatedUser: Pick<AuthenticatedUser, 'email'>
}

const signUpForm = new URL('https://share.hsforms.com/1tkScUc65Tm-Yu98zUZcLGw1n7ku')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this: This feels a bit weird because this URL is mutated on every render but shared between all instances of a component. This could cause issues when rendering it multiple times, e.g. in tests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't cause issues as set will just override any previous values but I agree this is a bit weird, PR to fix: https://github.com/sourcegraph/sourcegraph/pull/18171


export const ProductResearchPage: React.FunctionComponent<Props> = ({ telemetryService, authenticatedUser }) => {
useEffect(() => {
telemetryService.logViewEvent('UserSettingsProductResearch')
}, [telemetryService])

signUpForm.searchParams.set('email', authenticatedUser.email)

return (
<>
<h2 className="mb-3">Product research and feedback</h2>
<p>
Our product team conducts occasional research to learn about how you use Sourcegraph and ask for
feedback about upcoming ideas. Sign up to participate in our research and help us shape the future of
our product!
</p>
<a href={signUpForm.href} className="btn btn-primary mt-2" target="_blank" rel="noopener noreferrer">
Sign up now <OpenInNewIcon className="icon-inline" />
</a>
</>
)
}
6 changes: 6 additions & 0 deletions client/web/src/user/settings/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,10 @@ export const userSettingsAreaRoutes: readonly UserSettingsAreaRoute[] = [
exact: true,
condition: allowUserExternalServicePublic,
},
{
path: '/product-research',
exact: true,
render: lazyComponent(() => import('./research/ProductResearch'), 'ProductResearchPage'),
condition: () => window.context.productResearchPageEnabled,
},
]
5 changes: 5 additions & 0 deletions client/web/src/user/settings/sidebaritems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,10 @@ export const userSettingsSideBarItems: UserSettingsSidebarItems = {
to: '/repositories',
condition: allowUserExternalServicePublic,
},
{
label: 'Product research',
to: '/product-research',
condition: () => window.context.productResearchPageEnabled,
},
],
}
Loading