Skip to content

Commit 254a02f

Browse files
authored
chore(compass-e2e-tests): Add e2e tests for running an aggregation (#3111)
* chore(compass-e2e-tests): Add e2e tests for running an aggregation * chore(compass-e2e-tests): Only run cancel aggregation test for server 4.4+ * chore(compass-e2e-tests): Rename methods to describe behavior better; Remove unnneccessary last step from 'Run' tests
1 parent 1832477 commit 254a02f

File tree

7 files changed

+177
-7
lines changed

7 files changed

+177
-7
lines changed

packages/compass-aggregations/src/components/pipeline-results-workspace/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ export const PipelineResultsWorkspace: React.FunctionComponent<PipelineResultsWo
152152
results = (
153153
<ResultsContainer center>
154154
<CancelLoader
155-
dataTestId="pipeline-results-loader"
155+
data-testid="pipeline-results-loader"
156156
progressText={
157157
isMergeOrOutPipeline
158158
? `Persisting documents${

packages/compass-components/src/components/cancel-loader.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import CancelLoader from './cancel-loader';
99
function renderLoader(spy) {
1010
return render(
1111
<CancelLoader
12-
dataTestId="my-test-id"
12+
data-testid="my-test-id"
1313
progressText="Doing something"
1414
cancelText="Stop doing it"
1515
onCancel={spy}

packages/compass-components/src/components/cancel-loader.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ const textStyles = css({
2121
});
2222

2323
function CancelLoader({
24-
dataTestId,
24+
['data-testid']: dataTestId = 'cancel-loader',
2525
progressText,
2626
cancelText,
2727
onCancel,
2828
}: {
29-
dataTestId: string;
29+
'data-testid'?: string;
3030
progressText: string;
3131
cancelText: string;
3232
onCancel: () => void;
@@ -35,7 +35,11 @@ function CancelLoader({
3535
<div className={containerStyles} data-testid={dataTestId}>
3636
<SpinLoader size={`${spacing[4]}px`} />
3737
<Subtitle className={textStyles}>{progressText}</Subtitle>
38-
<Button variant="primaryOutline" onClick={onCancel}>
38+
<Button
39+
variant="primaryOutline"
40+
onClick={onCancel}
41+
data-testid={`${dataTestId}-button`}
42+
>
3943
{cancelText}
4044
</Button>
4145
</div>

packages/compass-crud/src/components/document-list.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class DocumentList extends React.Component {
101101
return (
102102
<div className="loader">
103103
<CancelLoader
104-
dataTestId="fetching-documents"
104+
data-testid="fetching-documents"
105105
progressText="Fetching Documents"
106106
cancelText="Stop"
107107
onCancel={this.onCancelClicked.bind(this)}

packages/compass-e2e-tests/helpers/selectors.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,23 @@ export const AggregationAdditionalOptionsButton =
592592
'[data-testid="pipeline-toolbar-options-button"]';
593593
export const AggregationCollationInput = '[data-testid="collation-string"]';
594594
export const AggregationMaxTimeMSInput = '[data-testid="max-time-ms"]';
595+
export const AggregationBuilderWorkspace =
596+
'[data-testid="pipeline-builder-workspace"]';
597+
export const AggregationResultsWorkspace =
598+
'[data-testid="pipeline-results-workspace"]';
599+
export const AggregationResultsDocumentListSwitchButton =
600+
'[aria-label="Document list"] button';
601+
export const AggregationResultsJSONListSwitchButton =
602+
'[aria-label="JSON list"] button';
603+
export const AggregationRestultsPaginationDescription =
604+
'[data-testid="pipeline-pagination-desc"]';
605+
export const AggregationRestultsNextPageButton =
606+
'[data-testid="pipeline-pagination-next-action"]';
607+
export const AggregationRestultsPrevPageButton =
608+
'[data-testid="pipeline-pagination-prev-action"]';
609+
export const AggregationResultsCancelButton =
610+
'[data-testid="pipeline-results-loader-button"]';
611+
export const AggregationEmptyResults = '[data-testid="pipeline-empty-results"]';
595612

596613
export const AggregationSettingsButton =
597614
'[data-testid="pipeline-toolbar-settings-button"]';
@@ -610,6 +627,7 @@ export const SavePipelineCreateViewAction =
610627
export const SavePipelineSaveAsAction = '[data-testid="save-menu-saveAs"]';
611628

612629
export const RunPipelineButton = `[data-testid="pipeline-toolbar-run-button"]`;
630+
export const EditPipelineButton = `[data-testid="pipeline-toolbar-edit-button"]`;
613631
export const GoToCollectionButton = `[data-testid="pipeline-results-go-to-collection"]`;
614632

615633
// Create view from pipeline modal

packages/compass-e2e-tests/tests/collection-aggregations-tab.test.ts

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,154 @@ describe('Collection aggregations tab', function () {
497497
});
498498
});
499499

500+
async function goToRunAggregation() {
501+
if (await browser.$(Selectors.AggregationBuilderWorkspace).isDisplayed()) {
502+
await browser.clickVisible(Selectors.RunPipelineButton);
503+
}
504+
const resultsWorkspace = await browser.$(
505+
Selectors.AggregationResultsWorkspace
506+
);
507+
await resultsWorkspace.waitForDisplayed();
508+
}
509+
510+
async function goToEditPipeline() {
511+
if (await browser.$(Selectors.AggregationResultsWorkspace).isDisplayed()) {
512+
await browser.clickVisible(Selectors.EditPipelineButton);
513+
}
514+
const builderWorkspace = await browser.$(
515+
Selectors.AggregationBuilderWorkspace
516+
);
517+
await builderWorkspace.waitForDisplayed();
518+
}
519+
520+
async function getDocuments() {
521+
// Switch to JSON view so it's easier to get document value
522+
await browser.clickVisible(
523+
Selectors.AggregationResultsJSONListSwitchButton
524+
);
525+
// Get all visible documents
526+
const documents = await browser.$$(Selectors.DocumentJSONEntry);
527+
// Get ace editor content and parse it
528+
const parsed = await Promise.all(
529+
documents.map(async (doc) => {
530+
const aceEditor = await doc.$('.ace_content');
531+
return JSON.parse(await aceEditor.getText());
532+
})
533+
);
534+
return parsed;
535+
}
536+
537+
it('supports running and editing aggregation', async function () {
538+
// Set first stage to match
539+
await browser.focusStageOperator(0);
540+
await browser.selectStageOperator(0, '$match');
541+
await browser.setAceValue(Selectors.stageEditor(0), '{ i: 5 }');
542+
543+
// Run and wait for results
544+
await goToRunAggregation();
545+
546+
// Get all documents from the current results page
547+
const docs = await getDocuments();
548+
549+
expect(docs).to.have.lengthOf(1);
550+
expect(docs[0]).to.have.property('_id');
551+
expect(docs[0]).to.have.property('i', 5);
552+
expect(docs[0]).to.have.property('j', 0);
553+
554+
// Go back to the pipeline builder
555+
await goToEditPipeline();
556+
557+
// Change match filter
558+
await browser.setAceValue(
559+
Selectors.stageEditor(0),
560+
'{ i: { $gte: 5, $lte: 10 } }'
561+
);
562+
563+
// Run and wait for results
564+
await goToRunAggregation();
565+
566+
// Get all documents from the current results page
567+
const updatedDocs = await getDocuments();
568+
569+
// Check that the documents are matching pipeline
570+
expect(updatedDocs).to.have.lengthOf(6);
571+
expect(updatedDocs[0]).to.have.property('i', 5);
572+
expect(updatedDocs[1]).to.have.property('i', 6);
573+
expect(updatedDocs[2]).to.have.property('i', 7);
574+
expect(updatedDocs[3]).to.have.property('i', 8);
575+
expect(updatedDocs[4]).to.have.property('i', 9);
576+
expect(updatedDocs[5]).to.have.property('i', 10);
577+
});
578+
579+
it('supports paginating aggregation results', async function () {
580+
// Set first stage to $match
581+
await browser.focusStageOperator(0);
582+
await browser.selectStageOperator(0, '$match');
583+
await browser.setAceValue(Selectors.stageEditor(0), '{ i: { $gte: 5 } }');
584+
585+
// Add second $limit stage
586+
await browser.clickVisible(Selectors.AddStageButton);
587+
await browser.focusStageOperator(1);
588+
await browser.selectStageOperator(1, '$limit');
589+
await browser.setAceValue(Selectors.stageEditor(1), '25');
590+
591+
// Run and wait for results
592+
await goToRunAggregation();
593+
594+
const page1 = await getDocuments();
595+
expect(page1).to.have.lengthOf(20);
596+
expect(page1[0]).to.have.property('i', 5);
597+
598+
await browser.clickVisible(Selectors.AggregationRestultsNextPageButton);
599+
await browser.waitUntil(async () => {
600+
const paginationDescription = await browser.$(
601+
Selectors.AggregationRestultsPaginationDescription
602+
);
603+
return (await paginationDescription.getText()) === 'Showing 21 – 25';
604+
});
605+
606+
const page2 = await getDocuments();
607+
expect(page2).to.have.lengthOf(5);
608+
expect(page2[0]).to.have.property('i', 25);
609+
});
610+
611+
it('supports cancelling long-running aggregations', async function () {
612+
if (semver.lt(MONGODB_VERSION, '4.4.0')) {
613+
// $function expression that we use to simulate slow aggregation is only
614+
// supported since server 4.4
615+
this.skip();
616+
}
617+
618+
const slowQuery = `{
619+
sleep: {
620+
$function: {
621+
body: function () {
622+
return sleep(10000) || true;
623+
},
624+
args: [],
625+
lang: "js",
626+
},
627+
},
628+
}`;
629+
630+
// Set first stage to a very slow $addFields
631+
await browser.focusStageOperator(0);
632+
await browser.selectStageOperator(0, '$addFields');
633+
await browser.setAceValue(Selectors.stageEditor(0), slowQuery);
634+
635+
// Run and wait for results
636+
await goToRunAggregation();
637+
638+
// Cancel aggregation run
639+
await browser.clickVisible(Selectors.AggregationResultsCancelButton);
640+
// Wait for the empty results banner (this is our indicator that we didn't
641+
// load anything and dismissed "Loading" banner)
642+
const emptyResultsBanner = await browser.$(
643+
Selectors.AggregationEmptyResults
644+
);
645+
await emptyResultsBanner.waitForDisplayed();
646+
});
647+
500648
// TODO: stages can be re-arranged by drag and drop and the preview is refreshed after rearranging them
501649
// TODO: test auto-preview and limit
502650
// TODO: save a pipeline, close compass, re-open compass, load the pipeline

packages/compass-schema/src/components/compass-schema/compass-schema.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class Schema extends Component {
177177
return (
178178
<div className={styles.loader}>
179179
<CancelLoader
180-
dataTestId="analyzing-documents"
180+
data-testid="analyzing-documents"
181181
progressText="Analyzing Documents"
182182
cancelText="Stop"
183183
onCancel={this.onCancelClicked.bind(this)}

0 commit comments

Comments
 (0)