mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 14:51:44 +00:00
Add integration test suite for campaigns (#13142)
This commit is contained in:
parent
09ddebfeae
commit
61d1098ce7
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -146,6 +146,7 @@
|
||||
/enterprise/cmd/frontend/internal/campaigns @sourcegraph/campaigns
|
||||
/internal/campaigns @sourcegraph/campaigns
|
||||
/web/**/campaigns/** @sourcegraph/campaigns
|
||||
/web/src/integration/campaigns.test.ts @sourcegraph/campaigns
|
||||
|
||||
# Search
|
||||
*/search/**/* @sourcegraph/search
|
||||
|
||||
@ -108,6 +108,7 @@ func addSharedTests(c Config) func(pipeline *bk.Pipeline) {
|
||||
// Client integration tests
|
||||
pipeline.AddStep(":puppeteer::electric_plug:",
|
||||
bk.Env("PUPPETEER_SKIP_CHROMIUM_DOWNLOAD", ""),
|
||||
bk.Env("ENTERPRISE", "1"),
|
||||
bk.Cmd("COVERAGE_INSTRUMENT=true dev/ci/yarn-run.sh build-web"),
|
||||
bk.Cmd("yarn run cover-integration"),
|
||||
bk.Cmd("yarn nyc report -r json"),
|
||||
|
||||
@ -89,7 +89,7 @@ export class FileDiffNode extends React.PureComponent<FileDiffNodeProps, State>
|
||||
return (
|
||||
<>
|
||||
<a id={anchor} />
|
||||
<div className={`file-diff-node card ${this.props.className || ''}`}>
|
||||
<div className={`file-diff-node test-file-diff-node card ${this.props.className || ''}`}>
|
||||
<div className="card-header file-diff-node__header">
|
||||
<button type="button" className="btn btn-sm btn-icon mr-2" onClick={this.toggleExpand}>
|
||||
{this.state.expanded ? (
|
||||
|
||||
@ -61,7 +61,7 @@ export const CampaignApplyPage: React.FunctionComponent<CampaignApplyPageProps>
|
||||
createdAt={spec.createdAt}
|
||||
creator={spec.creator}
|
||||
verb="Uploaded"
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-apply-page"
|
||||
/>
|
||||
<CreateUpdateCampaignAlert
|
||||
history={history}
|
||||
|
||||
@ -60,7 +60,7 @@ export const CreateUpdateCampaignAlert: React.FunctionComponent<CreateUpdateCamp
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(
|
||||
'btn btn-primary',
|
||||
'btn btn-primary test-campaigns-confirm-apply-btn',
|
||||
isLoading === true || (!viewerCanAdminister && 'disabled')
|
||||
)}
|
||||
onClick={onApply}
|
||||
|
||||
@ -61,7 +61,7 @@ export const VisibleChangesetSpecNode: React.FunctionComponent<VisibleChangesetS
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon"
|
||||
className="btn btn-icon test-campaigns-expand-changeset-spec"
|
||||
aria-label={isExpanded ? 'Collapse section' : 'Expand section'}
|
||||
onClick={toggleIsExpanded}
|
||||
>
|
||||
|
||||
@ -61,6 +61,7 @@ export const CampaignCloseAlert: React.FunctionComponent<CampaignCloseAlertProps
|
||||
type="checkbox"
|
||||
checked={closeChangesets}
|
||||
onChange={onChangeCloseChangesets}
|
||||
className="test-campaigns-close-changesets-checkbox"
|
||||
disabled={isClosing === true || !viewerCanAdminister}
|
||||
/>{' '}
|
||||
Also close open changesets on code hosts.
|
||||
@ -77,7 +78,7 @@ export const CampaignCloseAlert: React.FunctionComponent<CampaignCloseAlertProps
|
||||
<div className="d-flex justify-content-end">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-secondary mr-3"
|
||||
className="btn btn-secondary mr-3 test-campaigns-close-abort-btn"
|
||||
onClick={onCancel}
|
||||
disabled={isClosing === true || !viewerCanAdminister}
|
||||
>
|
||||
@ -85,7 +86,7 @@ export const CampaignCloseAlert: React.FunctionComponent<CampaignCloseAlertProps
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-danger"
|
||||
className="btn btn-danger test-campaigns-confirm-close-btn"
|
||||
onClick={onClose}
|
||||
disabled={isClosing === true || !viewerCanAdminister}
|
||||
>
|
||||
|
||||
@ -79,7 +79,7 @@ export const CampaignClosePage: React.FunctionComponent<CampaignClosePageProps>
|
||||
namespace={campaign.namespace}
|
||||
creator={campaign.initialApplier}
|
||||
createdAt={campaign.createdAt}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-close-page"
|
||||
/>
|
||||
<CampaignCloseAlert
|
||||
campaignID={campaignID}
|
||||
@ -90,7 +90,11 @@ export const CampaignClosePage: React.FunctionComponent<CampaignClosePageProps>
|
||||
closeCampaign={closeCampaign}
|
||||
viewerCanAdminister={campaign.viewerCanAdminister}
|
||||
/>
|
||||
{closeChangesets && <h2>Closing the campaign will close the following changesets:</h2>}
|
||||
{closeChangesets && (
|
||||
<h2 className="test-campaigns-close-willclose-header">
|
||||
Closing the campaign will close the following changesets:
|
||||
</h2>
|
||||
)}
|
||||
{!closeChangesets && <h2>The following changesets will remain open:</h2>}
|
||||
<CampaignCloseChangesetsList
|
||||
campaignID={campaignID}
|
||||
|
||||
@ -57,7 +57,7 @@ export const ExternalChangesetCloseNode: React.FunctionComponent<ExternalChanges
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon"
|
||||
className="btn btn-icon test-campaigns-expand-changeset"
|
||||
aria-label={isExpanded ? 'Collapse section' : 'Expand section'}
|
||||
onClick={toggleIsExpanded}
|
||||
>
|
||||
|
||||
@ -109,7 +109,7 @@ export const CampaignBurndownChart: React.FunctionComponent<Props> = ({
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ResponsiveContainer width={width} height={300}>
|
||||
<ResponsiveContainer width={width} height={300} className="test-campaigns-chart">
|
||||
<ComposedChart
|
||||
data={changesetCountsOverTime.map(snapshot => ({ ...snapshot, date: Date.parse(snapshot.date) }))}
|
||||
>
|
||||
|
||||
@ -115,7 +115,7 @@ export const CampaignDetails: React.FunctionComponent<CampaignDetailsProps> = ({
|
||||
history={history}
|
||||
/>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-details-page"
|
||||
/>
|
||||
<CampaignStatsCard closedAt={campaign.closedAt} stats={campaign.changesets.stats} className="mb-3" />
|
||||
<CampaignDescription history={history} description={campaign.description} />
|
||||
|
||||
@ -41,7 +41,7 @@ export const CampaignDetailsActionSection: React.FunctionComponent<CampaignDetai
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-danger"
|
||||
className="btn btn-outline-danger test-campaigns-delete-btn"
|
||||
onClick={onDeleteCampaign}
|
||||
data-tooltip="Deleting this campaign is a final action."
|
||||
disabled={isDeleting === true}
|
||||
@ -54,7 +54,7 @@ export const CampaignDetailsActionSection: React.FunctionComponent<CampaignDetai
|
||||
return (
|
||||
<Link
|
||||
to={`${location.pathname}/close`}
|
||||
className="btn btn-outline-danger"
|
||||
className="btn btn-outline-danger test-campaigns-close-btn"
|
||||
data-tooltip="View a preview of all changes that will happen when you close this campaign."
|
||||
>
|
||||
<DeleteIcon className="icon-inline" /> Close
|
||||
|
||||
@ -72,7 +72,7 @@ export const CampaignTabs: React.FunctionComponent<CampaignTabsProps> = ({
|
||||
<SourceBranchIcon className="icon-inline text-muted mr-1" /> Changesets
|
||||
</a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<li className="nav-item test-campaigns-chart-tab">
|
||||
<a
|
||||
href=""
|
||||
onClick={onSelectChart}
|
||||
|
||||
@ -38,12 +38,13 @@ exports[`CampaignBurndownChart renders the chart 1`] = `
|
||||
width={500}
|
||||
>
|
||||
<ResponsiveContainer
|
||||
className="test-campaigns-chart"
|
||||
debounce={0}
|
||||
height={300}
|
||||
width={500}
|
||||
>
|
||||
<div
|
||||
className="recharts-responsive-container"
|
||||
className="recharts-responsive-container test-campaigns-chart"
|
||||
style={
|
||||
Object {
|
||||
"height": 300,
|
||||
|
||||
@ -29,7 +29,7 @@ exports[`CampaignDetails viewerCanAdminister: false viewing existing 1`] = `
|
||||
history="[History]"
|
||||
/>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-details-page"
|
||||
createdAt="2020-01-01"
|
||||
creator={
|
||||
Object {
|
||||
@ -46,7 +46,7 @@ exports[`CampaignDetails viewerCanAdminister: false viewing existing 1`] = `
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="d-flex w-100 mb-2 justify-content-between align-items-center mb-3"
|
||||
className="d-flex w-100 mb-2 justify-content-between align-items-center mb-3 test-campaign-details-page"
|
||||
>
|
||||
<div>
|
||||
<h1
|
||||
@ -123,12 +123,12 @@ exports[`CampaignDetails viewerCanAdminister: false viewing existing 1`] = `
|
||||
history="[History]"
|
||||
>
|
||||
<AnchorLink
|
||||
className="btn btn-outline-danger"
|
||||
className="btn btn-outline-danger test-campaigns-close-btn"
|
||||
data-tooltip="View a preview of all changes that will happen when you close this campaign."
|
||||
to="//close"
|
||||
>
|
||||
<a
|
||||
className="btn btn-outline-danger"
|
||||
className="btn btn-outline-danger test-campaigns-close-btn"
|
||||
data-tooltip="View a preview of all changes that will happen when you close this campaign."
|
||||
href="//close"
|
||||
>
|
||||
@ -497,7 +497,7 @@ exports[`CampaignDetails viewerCanAdminister: false viewing existing 1`] = `
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
className="nav-item"
|
||||
className="nav-item test-campaigns-chart-tab"
|
||||
>
|
||||
<a
|
||||
className="nav-link"
|
||||
@ -810,7 +810,7 @@ exports[`CampaignDetails viewerCanAdminister: true viewing existing 1`] = `
|
||||
history="[History]"
|
||||
/>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-details-page"
|
||||
createdAt="2020-01-01"
|
||||
creator={
|
||||
Object {
|
||||
@ -827,7 +827,7 @@ exports[`CampaignDetails viewerCanAdminister: true viewing existing 1`] = `
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="d-flex w-100 mb-2 justify-content-between align-items-center mb-3"
|
||||
className="d-flex w-100 mb-2 justify-content-between align-items-center mb-3 test-campaign-details-page"
|
||||
>
|
||||
<div>
|
||||
<h1
|
||||
@ -904,12 +904,12 @@ exports[`CampaignDetails viewerCanAdminister: true viewing existing 1`] = `
|
||||
history="[History]"
|
||||
>
|
||||
<AnchorLink
|
||||
className="btn btn-outline-danger"
|
||||
className="btn btn-outline-danger test-campaigns-close-btn"
|
||||
data-tooltip="View a preview of all changes that will happen when you close this campaign."
|
||||
to="//close"
|
||||
>
|
||||
<a
|
||||
className="btn btn-outline-danger"
|
||||
className="btn btn-outline-danger test-campaigns-close-btn"
|
||||
data-tooltip="View a preview of all changes that will happen when you close this campaign."
|
||||
href="//close"
|
||||
>
|
||||
@ -1278,7 +1278,7 @@ exports[`CampaignDetails viewerCanAdminister: true viewing existing 1`] = `
|
||||
</a>
|
||||
</li>
|
||||
<li
|
||||
className="nav-item"
|
||||
className="nav-item test-campaigns-chart-tab"
|
||||
>
|
||||
<a
|
||||
className="nav-link"
|
||||
|
||||
@ -55,7 +55,7 @@ export const ExternalChangesetNode: React.FunctionComponent<ExternalChangesetNod
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon"
|
||||
className="btn btn-icon test-campaigns-expand-changeset"
|
||||
aria-label={isExpanded ? 'Collapse section' : 'Expand section'}
|
||||
onClick={toggleIsExpanded}
|
||||
>
|
||||
|
||||
@ -4,7 +4,7 @@ exports[`ExternalChangesetNode renders an externalchangeset 1`] = `
|
||||
<Fragment>
|
||||
<button
|
||||
aria-label="Expand section"
|
||||
className="btn btn-icon"
|
||||
className="btn btn-icon test-campaigns-expand-changeset"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
|
||||
@ -55,7 +55,7 @@ export const CampaignListPage: React.FunctionComponent<Props> = ({
|
||||
return (
|
||||
<>
|
||||
<CampaignHeader
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-list-page"
|
||||
actionSection={
|
||||
<Link to={`${location.pathname}/create`} className="btn btn-primary">
|
||||
<PlusIcon className="icon-inline" /> New campaign
|
||||
|
||||
@ -48,13 +48,18 @@ export const CampaignNode: React.FunctionComponent<CampaignNodeProps> = ({
|
||||
<h3 className="m-0 d-inline-block">
|
||||
{displayNamespace && (
|
||||
<>
|
||||
<Link className="text-muted" to={`${node.namespace.url}/campaigns`}>
|
||||
<Link
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
to={`${node.namespace.url}/campaigns`}
|
||||
>
|
||||
{node.namespace.namespaceName}
|
||||
</Link>
|
||||
<span className="text-muted d-inline-block mx-1">/</span>
|
||||
</>
|
||||
)}
|
||||
<Link to={node.url}>{node.name}</Link>
|
||||
<Link className="test-campaign-link" to={node.url}>
|
||||
{node.name}
|
||||
</Link>
|
||||
</h3>
|
||||
<small className="ml-2 text-muted">
|
||||
created{' '}
|
||||
|
||||
@ -14,7 +14,7 @@ exports[`CampaignListPage renders for non-siteadmin and totalCount: 0 1`] = `
|
||||
New campaign
|
||||
</AnchorLink>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-list-page"
|
||||
/>
|
||||
<CampaignsListBetaNotice />
|
||||
<FilteredConnection
|
||||
@ -87,7 +87,7 @@ exports[`CampaignListPage renders for non-siteadmin and totalCount: 1 1`] = `
|
||||
New campaign
|
||||
</AnchorLink>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-list-page"
|
||||
/>
|
||||
<CampaignsListBetaNotice />
|
||||
<FilteredConnection
|
||||
@ -160,7 +160,7 @@ exports[`CampaignListPage renders for siteadmin and totalCount: 0 1`] = `
|
||||
New campaign
|
||||
</AnchorLink>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-list-page"
|
||||
/>
|
||||
<CampaignsListBetaNotice />
|
||||
<FilteredConnection
|
||||
@ -233,7 +233,7 @@ exports[`CampaignListPage renders for siteadmin and totalCount: 1 1`] = `
|
||||
New campaign
|
||||
</AnchorLink>
|
||||
}
|
||||
className="mb-3"
|
||||
className="mb-3 test-campaign-list-page"
|
||||
/>
|
||||
<CampaignsListBetaNotice />
|
||||
<FilteredConnection
|
||||
|
||||
@ -49,11 +49,11 @@ exports[`CampaignNode campaign without description 1`] = `
|
||||
className="m-0 d-inline-block"
|
||||
>
|
||||
<AnchorLink
|
||||
className="text-muted"
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
to="/users/alice/campaigns"
|
||||
>
|
||||
<a
|
||||
className="text-muted"
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
href="/users/alice/campaigns"
|
||||
>
|
||||
alice
|
||||
@ -65,9 +65,11 @@ exports[`CampaignNode campaign without description 1`] = `
|
||||
/
|
||||
</span>
|
||||
<AnchorLink
|
||||
className="test-campaign-link"
|
||||
to="/users/alice/campaigns/123"
|
||||
>
|
||||
<a
|
||||
className="test-campaign-link"
|
||||
href="/users/alice/campaigns/123"
|
||||
>
|
||||
Upgrade lodash to v4
|
||||
@ -265,11 +267,11 @@ exports[`CampaignNode closed campaign 1`] = `
|
||||
className="m-0 d-inline-block"
|
||||
>
|
||||
<AnchorLink
|
||||
className="text-muted"
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
to="/users/alice/campaigns"
|
||||
>
|
||||
<a
|
||||
className="text-muted"
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
href="/users/alice/campaigns"
|
||||
>
|
||||
alice
|
||||
@ -281,9 +283,11 @@ exports[`CampaignNode closed campaign 1`] = `
|
||||
/
|
||||
</span>
|
||||
<AnchorLink
|
||||
className="test-campaign-link"
|
||||
to="/users/alice/campaigns/123"
|
||||
>
|
||||
<a
|
||||
className="test-campaign-link"
|
||||
href="/users/alice/campaigns/123"
|
||||
>
|
||||
Upgrade lodash to v4
|
||||
@ -489,11 +493,11 @@ exports[`CampaignNode open campaign 1`] = `
|
||||
className="m-0 d-inline-block"
|
||||
>
|
||||
<AnchorLink
|
||||
className="text-muted"
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
to="/users/alice/campaigns"
|
||||
>
|
||||
<a
|
||||
className="text-muted"
|
||||
className="text-muted test-campaign-namespace-link"
|
||||
href="/users/alice/campaigns"
|
||||
>
|
||||
alice
|
||||
@ -505,9 +509,11 @@ exports[`CampaignNode open campaign 1`] = `
|
||||
/
|
||||
</span>
|
||||
<AnchorLink
|
||||
className="test-campaign-link"
|
||||
to="/users/alice/campaigns/123"
|
||||
>
|
||||
<a
|
||||
className="test-campaign-link"
|
||||
href="/users/alice/campaigns/123"
|
||||
>
|
||||
Upgrade lodash to v4
|
||||
@ -713,9 +719,11 @@ exports[`CampaignNode open campaign on user page 1`] = `
|
||||
className="m-0 d-inline-block"
|
||||
>
|
||||
<AnchorLink
|
||||
className="test-campaign-link"
|
||||
to="/users/alice/campaigns/123"
|
||||
>
|
||||
<a
|
||||
className="test-campaign-link"
|
||||
href="/users/alice/campaigns/123"
|
||||
>
|
||||
Upgrade lodash to v4
|
||||
|
||||
644
web/src/integration/campaigns.test.ts
Normal file
644
web/src/integration/campaigns.test.ts
Normal file
@ -0,0 +1,644 @@
|
||||
import assert from 'assert'
|
||||
import { createDriverForTest, Driver } from '../../../shared/src/testing/driver'
|
||||
import { commonWebGraphQlResults } from './graphQlResults'
|
||||
import { createWebIntegrationTestContext, WebIntegrationTestContext } from './context'
|
||||
import { saveScreenshotsUponFailures } from '../../../shared/src/testing/screenshotReporter'
|
||||
import { subDays, addDays } from 'date-fns'
|
||||
import { createJsContext } from './jscontext'
|
||||
import {
|
||||
ChangesetCheckState,
|
||||
ChangesetExternalState,
|
||||
ChangesetPublicationState,
|
||||
ChangesetReconcilerState,
|
||||
ChangesetReviewState,
|
||||
ChangesetCountsOverTimeVariables,
|
||||
ChangesetCountsOverTimeResult,
|
||||
ExternalChangesetFileDiffsVariables,
|
||||
ExternalChangesetFileDiffsResult,
|
||||
CampaignChangesetsVariables,
|
||||
CampaignChangesetsResult,
|
||||
WebGraphQlOperations,
|
||||
CampaignByIDResult,
|
||||
ExternalChangesetFileDiffsFields,
|
||||
DiffHunkLineType,
|
||||
ChangesetSpecType,
|
||||
ListCampaign,
|
||||
} from '../graphql-operations'
|
||||
import { SharedGraphQlOperations } from '../../../shared/src/graphql-operations'
|
||||
|
||||
const campaignListNode: ListCampaign = {
|
||||
id: 'campaign123',
|
||||
url: '/users/alice/campaigns/campaign123',
|
||||
name: 'campaign123',
|
||||
createdAt: subDays(new Date(), 5).toISOString(),
|
||||
changesets: { stats: { closed: 4, merged: 10, open: 5 } },
|
||||
closedAt: null,
|
||||
description: null,
|
||||
namespace: {
|
||||
namespaceName: 'alice',
|
||||
url: '/users/alice',
|
||||
},
|
||||
}
|
||||
|
||||
const mockDiff: NonNullable<ExternalChangesetFileDiffsFields['diff']> = {
|
||||
__typename: 'RepositoryComparison',
|
||||
fileDiffs: {
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'FileDiff',
|
||||
internalID: 'intid123',
|
||||
oldPath: '/somefile.md',
|
||||
newPath: '/somefile.md',
|
||||
oldFile: {
|
||||
__typename: 'GitBlob',
|
||||
binary: false,
|
||||
byteSize: 0,
|
||||
},
|
||||
newFile: {
|
||||
__typename: 'GitBlob',
|
||||
binary: false,
|
||||
byteSize: 0,
|
||||
},
|
||||
mostRelevantFile: {
|
||||
__typename: 'GitBlob',
|
||||
url: 'http://test.test/fileurl',
|
||||
},
|
||||
hunks: [
|
||||
{
|
||||
section: "@@ -70,33 +81,154 @@ super('awesome', () => {",
|
||||
oldRange: {
|
||||
startLine: 70,
|
||||
lines: 33,
|
||||
},
|
||||
newRange: {
|
||||
startLine: 81,
|
||||
lines: 154,
|
||||
},
|
||||
oldNoNewlineAt: false,
|
||||
highlight: {
|
||||
aborted: false,
|
||||
lines: [
|
||||
{
|
||||
html: 'some fiel content',
|
||||
kind: DiffHunkLineType.DELETED,
|
||||
},
|
||||
{
|
||||
html: 'some file content',
|
||||
kind: DiffHunkLineType.ADDED,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
stat: {
|
||||
added: 10,
|
||||
changed: 3,
|
||||
deleted: 8,
|
||||
},
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: null,
|
||||
hasNextPage: false,
|
||||
},
|
||||
totalCount: 1,
|
||||
},
|
||||
range: {
|
||||
base: {
|
||||
__typename: 'GitRef',
|
||||
target: {
|
||||
oid: 'abc123base',
|
||||
},
|
||||
},
|
||||
head: {
|
||||
__typename: 'GitRef',
|
||||
target: {
|
||||
oid: 'abc123head',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const ChangesetCountsOverTime: (variables: ChangesetCountsOverTimeVariables) => ChangesetCountsOverTimeResult = () => ({
|
||||
node: {
|
||||
__typename: 'Campaign',
|
||||
changesetCountsOverTime: [
|
||||
{
|
||||
closed: 12,
|
||||
date: subDays(new Date(), 2).toISOString(),
|
||||
merged: 10,
|
||||
openApproved: 3,
|
||||
openChangesRequested: 1,
|
||||
openPending: 91,
|
||||
total: 130,
|
||||
},
|
||||
{
|
||||
closed: 12,
|
||||
date: subDays(new Date(), 1).toISOString(),
|
||||
merged: 10,
|
||||
openApproved: 23,
|
||||
openChangesRequested: 1,
|
||||
openPending: 71,
|
||||
total: 130,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
const ExternalChangesetFileDiffs: (
|
||||
variables: ExternalChangesetFileDiffsVariables
|
||||
) => ExternalChangesetFileDiffsResult = () => ({
|
||||
node: {
|
||||
__typename: 'ExternalChangeset',
|
||||
diff: mockDiff,
|
||||
},
|
||||
})
|
||||
|
||||
const CampaignChangesets: (variables: CampaignChangesetsVariables) => CampaignChangesetsResult = () => ({
|
||||
node: {
|
||||
__typename: 'Campaign',
|
||||
changesets: {
|
||||
totalCount: 1,
|
||||
pageInfo: {
|
||||
endCursor: null,
|
||||
hasNextPage: false,
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'ExternalChangeset',
|
||||
body: 'body123',
|
||||
checkState: ChangesetCheckState.PASSED,
|
||||
createdAt: subDays(new Date(), 5).toISOString(),
|
||||
updatedAt: subDays(new Date(), 5).toISOString(),
|
||||
diffStat: {
|
||||
added: 100,
|
||||
changed: 10,
|
||||
deleted: 23,
|
||||
},
|
||||
error: null,
|
||||
externalID: '123',
|
||||
externalState: ChangesetExternalState.OPEN,
|
||||
externalURL: {
|
||||
url: 'http://test.test/123',
|
||||
},
|
||||
id: 'changeset123',
|
||||
labels: [
|
||||
{
|
||||
color: '93ba13',
|
||||
description: null,
|
||||
text: 'Abc label',
|
||||
},
|
||||
],
|
||||
nextSyncAt: null,
|
||||
publicationState: ChangesetPublicationState.PUBLISHED,
|
||||
reconcilerState: ChangesetReconcilerState.COMPLETED,
|
||||
repository: {
|
||||
id: 'repo123',
|
||||
name: 'github.com/sourcegraph/repo',
|
||||
url: 'http://test.test/repo',
|
||||
},
|
||||
reviewState: ChangesetReviewState.APPROVED,
|
||||
title: 'The changeset title',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
function mockCommonGraphQLResponses(
|
||||
entityType: 'user' | 'org',
|
||||
campaignOverrides?: Partial<NonNullable<CampaignByIDResult['node']>>
|
||||
): Partial<WebGraphQlOperations & SharedGraphQlOperations> {
|
||||
const namespaceURL = entityType === 'user' ? '/users/alice' : '/organizations/test-org'
|
||||
return {
|
||||
Organization: () => ({
|
||||
organization: {
|
||||
__typename: 'Org',
|
||||
createdAt: '2020-08-07T00:00',
|
||||
displayName: 'test-org',
|
||||
settingsURL: `${namespaceURL}/settings`,
|
||||
id: 'TestOrg',
|
||||
name: 'test-org',
|
||||
url: namespaceURL,
|
||||
viewerCanAdminister: true,
|
||||
viewerIsMember: false,
|
||||
viewerPendingInvitation: null,
|
||||
},
|
||||
}),
|
||||
User: () => ({
|
||||
user: {
|
||||
__typename: 'User',
|
||||
id: 'user123',
|
||||
username: 'alice',
|
||||
displayName: 'alice',
|
||||
url: namespaceURL,
|
||||
settingsURL: `${namespaceURL}/settings`,
|
||||
avatarURL: '',
|
||||
viewerCanAdminister: true,
|
||||
siteAdmin: true,
|
||||
builtinAuth: true,
|
||||
createdAt: '2020-04-10T21:11:42Z',
|
||||
emails: [{ email: 'alice@example.com', verified: true }],
|
||||
organizations: { nodes: [] },
|
||||
permissionsInfo: null,
|
||||
},
|
||||
}),
|
||||
CampaignByID: () => ({
|
||||
node: {
|
||||
__typename: 'Campaign',
|
||||
id: 'campaign123',
|
||||
changesets: { stats: { closed: 2, merged: 3, open: 10, total: 5, unpublished: 3 } },
|
||||
closedAt: null,
|
||||
createdAt: subDays(new Date(), 5).toISOString(),
|
||||
updatedAt: subDays(new Date(), 5).toISOString(),
|
||||
description: '### Very cool campaign',
|
||||
initialApplier: {
|
||||
url: '/users/alice',
|
||||
username: 'alice',
|
||||
},
|
||||
name: 'test-campaign',
|
||||
namespace: {
|
||||
namespaceName: entityType === 'user' ? 'alice' : 'test-org',
|
||||
url: namespaceURL,
|
||||
},
|
||||
url: `${namespaceURL}/campaigns/campaign123`,
|
||||
diffStat: {
|
||||
added: 1000,
|
||||
changed: 29,
|
||||
deleted: 817,
|
||||
},
|
||||
viewerCanAdminister: true,
|
||||
...campaignOverrides,
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
describe('Campaigns', () => {
|
||||
let driver: Driver
|
||||
before(async () => {
|
||||
driver = await createDriverForTest()
|
||||
})
|
||||
after(() => driver?.close())
|
||||
let testContext: WebIntegrationTestContext
|
||||
beforeEach(async function () {
|
||||
testContext = await createWebIntegrationTestContext({
|
||||
driver,
|
||||
currentTest: this.currentTest!,
|
||||
directory: __dirname,
|
||||
})
|
||||
testContext.overrideJsContext({
|
||||
...createJsContext({
|
||||
sourcegraphBaseUrl: testContext.driver.sourcegraphBaseUrl,
|
||||
}),
|
||||
experimentalFeatures: { automation: 'enabled' },
|
||||
})
|
||||
})
|
||||
saveScreenshotsUponFailures(() => driver.page)
|
||||
afterEach(() => testContext?.dispose())
|
||||
|
||||
describe('Campaigns list', () => {
|
||||
it('lists global campaigns', async () => {
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
Campaigns: () => ({
|
||||
campaigns: {
|
||||
nodes: [campaignListNode],
|
||||
pageInfo: {
|
||||
endCursor: null,
|
||||
hasNextPage: false,
|
||||
},
|
||||
totalCount: 1,
|
||||
},
|
||||
}),
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/campaigns')
|
||||
await driver.page.waitForSelector('.test-campaign-list-page')
|
||||
await driver.page.waitForSelector('.test-campaign-namespace-link')
|
||||
await driver.page.waitForSelector('.test-campaign-link')
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(
|
||||
() => document.querySelector<HTMLAnchorElement>('.test-campaign-namespace-link')?.href
|
||||
),
|
||||
testContext.driver.sourcegraphBaseUrl + '/users/alice/campaigns'
|
||||
)
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(
|
||||
() => document.querySelector<HTMLAnchorElement>('.test-campaign-link')?.href
|
||||
),
|
||||
testContext.driver.sourcegraphBaseUrl + '/users/alice/campaigns/campaign123'
|
||||
)
|
||||
})
|
||||
|
||||
it('lists user campaigns', async () => {
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
...mockCommonGraphQLResponses('user'),
|
||||
CampaignsByUser: () => ({
|
||||
node: {
|
||||
__typename: 'User',
|
||||
campaigns: {
|
||||
nodes: [campaignListNode],
|
||||
pageInfo: {
|
||||
endCursor: null,
|
||||
hasNextPage: false,
|
||||
},
|
||||
totalCount: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/users/alice/campaigns')
|
||||
|
||||
await driver.page.waitForSelector('.test-campaign-list-page')
|
||||
await driver.page.waitForSelector('.test-campaign-link')
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(
|
||||
() => document.querySelector<HTMLAnchorElement>('.test-campaign-link')?.href
|
||||
),
|
||||
testContext.driver.sourcegraphBaseUrl + '/users/alice/campaigns/campaign123'
|
||||
)
|
||||
assert.strictEqual(await driver.page.$('.test-campaign-namespace-link'), null)
|
||||
})
|
||||
|
||||
it('lists org campaigns', async () => {
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
...mockCommonGraphQLResponses('org'),
|
||||
CampaignsByOrg: () => ({
|
||||
node: {
|
||||
__typename: 'Org',
|
||||
campaigns: {
|
||||
nodes: [
|
||||
{
|
||||
...campaignListNode,
|
||||
url: '/organizations/test-org/campaigns/campaign123',
|
||||
namespace: {
|
||||
namespaceName: 'test-org',
|
||||
url: '/organizations/test-org',
|
||||
},
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: null,
|
||||
hasNextPage: false,
|
||||
},
|
||||
totalCount: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
})
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/campaigns')
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + '/organizations/test-org/campaigns')
|
||||
await driver.page.waitForSelector('.test-campaign-list-page')
|
||||
await driver.page.waitForSelector('.test-campaign-link')
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(
|
||||
() => document.querySelector<HTMLAnchorElement>('.test-campaign-link')?.href
|
||||
),
|
||||
testContext.driver.sourcegraphBaseUrl + '/organizations/test-org/campaigns/campaign123'
|
||||
)
|
||||
assert.strictEqual(await driver.page.$('.test-campaign-namespace-link'), null)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Campaign details', () => {
|
||||
for (const entityType of ['user', 'org'] as const) {
|
||||
it(`displays a single campaign for ${entityType}`, async () => {
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
...mockCommonGraphQLResponses(entityType),
|
||||
CampaignChangesets,
|
||||
ChangesetCountsOverTime,
|
||||
ExternalChangesetFileDiffs,
|
||||
})
|
||||
const namespaceURL = entityType === 'user' ? '/users/alice' : '/organizations/test-org'
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/campaign123')
|
||||
// View overview page.
|
||||
await driver.page.waitForSelector('.test-campaign-details-page')
|
||||
|
||||
// Expand one changeset.
|
||||
await driver.page.click('.test-campaigns-expand-changeset')
|
||||
// Expect one diff to be rendered.
|
||||
await driver.page.waitForSelector('.test-file-diff-node')
|
||||
|
||||
// Switch to view burndown chart.
|
||||
await driver.page.click('.test-campaigns-chart-tab')
|
||||
await driver.page.waitForSelector('.test-campaigns-chart')
|
||||
|
||||
// Go to close page via button.
|
||||
await Promise.all([driver.page.waitForNavigation(), driver.page.click('.test-campaigns-close-btn')])
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(() => window.location.href),
|
||||
testContext.driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/campaign123/close'
|
||||
)
|
||||
await driver.page.waitForSelector('.test-campaign-close-page')
|
||||
// Change overrides to make campaign appear closed.
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
...mockCommonGraphQLResponses(entityType, { closedAt: subDays(new Date(), 1).toISOString() }),
|
||||
CampaignChangesets,
|
||||
ChangesetCountsOverTime,
|
||||
ExternalChangesetFileDiffs,
|
||||
DeleteCampaign: () => ({
|
||||
deleteCampaign: {
|
||||
alwaysNil: null,
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
// Return to details page.
|
||||
await Promise.all([
|
||||
driver.page.waitForNavigation(),
|
||||
driver.page.click('.test-campaigns-close-abort-btn'),
|
||||
])
|
||||
await driver.page.waitForSelector('.test-campaign-details-page')
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(() => window.location.href),
|
||||
testContext.driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/campaign123'
|
||||
)
|
||||
|
||||
// Delete the closed campaign.
|
||||
await Promise.all([
|
||||
driver.page.waitForNavigation(),
|
||||
driver.acceptNextDialog(),
|
||||
driver.page.click('.test-campaigns-delete-btn'),
|
||||
])
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(() => window.location.href),
|
||||
testContext.driver.sourcegraphBaseUrl + namespaceURL + '/campaigns'
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('Campaign spec preview', () => {
|
||||
for (const entityType of ['user', 'org'] as const) {
|
||||
it(`displays a preview of a campaign spec in ${entityType} namespace`, async () => {
|
||||
const namespaceURL = entityType === 'user' ? '/users/alice' : '/organizations/test-org'
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
...mockCommonGraphQLResponses(entityType),
|
||||
CampaignSpecByID: () => ({
|
||||
node: {
|
||||
__typename: 'CampaignSpec',
|
||||
id: 'spec123',
|
||||
appliesToCampaign: null,
|
||||
createdAt: subDays(new Date(), 2).toISOString(),
|
||||
creator: {
|
||||
username: 'alice',
|
||||
url: '/users/alice',
|
||||
avatarURL: null,
|
||||
},
|
||||
description: {
|
||||
name: 'test-campaign',
|
||||
description: '### Very great campaign',
|
||||
},
|
||||
diffStat: {
|
||||
added: 1000,
|
||||
changed: 100,
|
||||
deleted: 182,
|
||||
},
|
||||
expiresAt: addDays(new Date(), 3).toISOString(),
|
||||
namespace:
|
||||
entityType === 'user'
|
||||
? {
|
||||
namespaceName: 'alice',
|
||||
url: '/users/alice',
|
||||
}
|
||||
: {
|
||||
namespaceName: 'test-org',
|
||||
url: '/organizations/test-org',
|
||||
},
|
||||
viewerCanAdminister: true,
|
||||
},
|
||||
}),
|
||||
CampaignSpecChangesetSpecs: () => ({
|
||||
node: {
|
||||
__typename: 'CampaignSpec',
|
||||
changesetSpecs: {
|
||||
nodes: [
|
||||
{
|
||||
__typename: 'VisibleChangesetSpec',
|
||||
description: {
|
||||
__typename: 'GitBranchChangesetDescription',
|
||||
baseRef: 'main',
|
||||
headRef: 'head-ref',
|
||||
baseRepository: {
|
||||
name: 'github.com/sourcegraph/repo',
|
||||
url: 'http://test.test/repo',
|
||||
},
|
||||
published: true,
|
||||
body: 'Body',
|
||||
commits: [
|
||||
{
|
||||
message: 'Commit message',
|
||||
},
|
||||
],
|
||||
diffStat: {
|
||||
added: 10,
|
||||
changed: 2,
|
||||
deleted: 9,
|
||||
},
|
||||
title: 'Changeset title',
|
||||
},
|
||||
expiresAt: addDays(new Date(), 3).toISOString(),
|
||||
id: 'changesetspec123',
|
||||
type: ChangesetSpecType.BRANCH,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
endCursor: null,
|
||||
hasNextPage: false,
|
||||
},
|
||||
totalCount: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
ChangesetSpecFileDiffs: () => ({
|
||||
node: {
|
||||
__typename: 'VisibleChangesetSpec',
|
||||
description: {
|
||||
__typename: 'GitBranchChangesetDescription',
|
||||
diff: mockDiff,
|
||||
},
|
||||
},
|
||||
}),
|
||||
CreateCampaign: () => ({
|
||||
createCampaign: {
|
||||
id: 'campaign123',
|
||||
url: namespaceURL + '/campaigns/campaign123',
|
||||
},
|
||||
}),
|
||||
})
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/apply/spec123')
|
||||
// View overview page.
|
||||
await driver.page.waitForSelector('.test-campaign-apply-page')
|
||||
|
||||
// Expand one changeset.
|
||||
await driver.page.click('.test-campaigns-expand-changeset-spec')
|
||||
// Expect one diff to be rendered.
|
||||
await driver.page.waitForSelector('.test-file-diff-node')
|
||||
|
||||
// Apply campaign.
|
||||
await Promise.all([
|
||||
driver.page.waitForNavigation(),
|
||||
driver.acceptNextDialog(),
|
||||
driver.page.click('.test-campaigns-confirm-apply-btn'),
|
||||
])
|
||||
// Expect to be back at campaign overview page.
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(() => window.location.href),
|
||||
testContext.driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/campaign123'
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
describe('Campaign close preview', () => {
|
||||
for (const entityType of ['user', 'org'] as const) {
|
||||
it(`displays a preview for closing a campaign in ${entityType} namespace`, async () => {
|
||||
testContext.overrideGraphQL({
|
||||
...commonWebGraphQlResults,
|
||||
...mockCommonGraphQLResponses(entityType),
|
||||
CampaignChangesets,
|
||||
ExternalChangesetFileDiffs,
|
||||
CloseCampaign: () => ({
|
||||
closeCampaign: {
|
||||
id: 'campaign123',
|
||||
},
|
||||
}),
|
||||
})
|
||||
const namespaceURL = entityType === 'user' ? '/users/alice' : '/organizations/test-org'
|
||||
|
||||
await driver.page.goto(driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/campaign123/close')
|
||||
// View overview page.
|
||||
await driver.page.waitForSelector('.test-campaign-close-page')
|
||||
|
||||
// Check close changesets box.
|
||||
assert.strictEqual(await driver.page.$('.test-campaigns-close-willclose-header'), null)
|
||||
await driver.page.click('.test-campaigns-close-changesets-checkbox')
|
||||
await driver.page.waitForSelector('.test-campaigns-close-willclose-header')
|
||||
|
||||
// Expand one changeset.
|
||||
await driver.page.click('.test-campaigns-expand-changeset')
|
||||
// Expect one diff to be rendered.
|
||||
await driver.page.waitForSelector('.test-file-diff-node')
|
||||
|
||||
// Close campaign.
|
||||
await Promise.all([
|
||||
driver.page.waitForNavigation(),
|
||||
driver.page.click('.test-campaigns-confirm-close-btn'),
|
||||
])
|
||||
// Expect to be back at campaign overview page.
|
||||
assert.strictEqual(
|
||||
await driver.page.evaluate(() => window.location.href),
|
||||
testContext.driver.sourcegraphBaseUrl + namespaceURL + '/campaigns/campaign123'
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user