Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ describe('PipelineResultsWorkspace', function () {
const onRetry = spy();
await renderPipelineResultsWorkspace({
isError: true,
error: 'Something bad happened',
error: { message: 'Something bad happened' },
onRetry,
});
expect(screen.getByText('Something bad happened')).to.exist;
userEvent.click(screen.getByText('Retry'), undefined, {
userEvent.click(screen.getByText('RETRY'), undefined, {
skipPointerEventsCheck: true,
});
expect(onRetry).to.be.calledOnce;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ import {
cx,
spacing,
CancelLoader,
ErrorSummary,
Subtitle,
Button,
palette,
Banner,
BannerVariant,
showErrorDetails,
} from '@mongodb-js/compass-components';
import type { RootState } from '../../modules';
import { cancelAggregation, retryAggregation } from '../../modules/aggregation';
import {
type AggregationError,
cancelAggregation,
retryAggregation,
} from '../../modules/aggregation';
import PipelineResultsList from './pipeline-results-list';
import PipelineEmptyResults from './pipeline-empty-results';
import {
Expand Down Expand Up @@ -52,6 +58,23 @@ const centered = css({
justifyContent: 'center',
});

const errorBannerStyles = css({
width: '100%',
});

const errorBannerContentStyles = css({
display: 'flex',
justifyContent: 'space-between',
});

const errorBannerTextStyles = css({
flex: 1,
});

const errorDetailsBtnStyles = css({
marginLeft: spacing[100],
});

const ResultsContainer: React.FunctionComponent<{ center?: boolean }> = ({
children,
center,
Expand Down Expand Up @@ -102,7 +125,7 @@ type PipelineResultsWorkspaceProps = {
documents: HadronDocument[];
isLoading?: boolean;
isError?: boolean;
error?: string | null;
error?: AggregationError;
isEmpty?: boolean;
isMergeOrOutPipeline?: boolean;
mergeOrOutDestination?: string | null;
Expand Down Expand Up @@ -133,12 +156,38 @@ export const PipelineResultsWorkspace: React.FunctionComponent<
if (isError && error) {
results = (
<ResultsContainer>
<ErrorSummary
<Banner
data-testid="pipeline-results-error"
errors={error}
onAction={onRetry}
actionText="Retry"
/>
variant={BannerVariant.Danger}
className={errorBannerStyles}
>
<div className={errorBannerContentStyles}>
<div className={errorBannerTextStyles}>{error?.message}</div>
<Button
size="xsmall"
onClick={onRetry}
data-testid="pipeline-results-error-retry-button"
className={errorDetailsBtnStyles}
>
RETRY
</Button>
{error?.info && (
<Button
size="xsmall"
onClick={() =>
showErrorDetails({
details: error.info!,
closeAction: 'close',
})
}
data-testid="pipeline-results-error-details-button"
className={errorDetailsBtnStyles}
>
VIEW ERROR DETAILS
</Button>
)}
</div>
</Banner>
</ResultsContainer>
);
} else if (isLoading) {
Expand Down
18 changes: 15 additions & 3 deletions packages/compass-aggregations/src/modules/aggregation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,14 @@ export type AggregationFinishedAction = {
isLast: boolean;
};

export type AggregationError = {
message: string;
info?: Record<string, unknown>;
};

export type AggregationFailedAction = {
type: ActionTypes.AggregationFailed;
error: string;
error: AggregationError;
page: number;
};

Expand Down Expand Up @@ -110,7 +115,7 @@ export type State = {
isLast: boolean;
loading: boolean;
abortController?: AbortController;
error?: string;
error?: AggregationError;
previousPageData?: PreviousPageData;
resultsViewType: 'document' | 'json';
};
Expand All @@ -125,6 +130,13 @@ export const INITIAL_STATE: State = {
resultsViewType: 'document',
};

function getAggregationError(error: Error): AggregationError {
return {
message: error.message,
info: (error as MongoServerError).errInfo,
};
}

const reducer: Reducer<State, Action> = (state = INITIAL_STATE, action) => {
if (
isAction<WorkspaceChangedAction>(
Expand Down Expand Up @@ -477,7 +489,7 @@ const fetchAggregationData = (
if ((e as MongoServerError).code) {
dispatch({
type: ActionTypes.AggregationFailed,
error: (e as Error).message,
error: getAggregationError(e as Error),
page,
});
if ((e as MongoServerError).codeName === 'MaxTimeMSExpired') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ export async function setValidation(
collection,
'Validation'
);
await browser.clickVisible(Selectors.AddRuleButton);
const startButton = browser.$(Selectors.AddRuleButton);
if (await startButton.isExisting()) {
await browser.clickVisible(startButton);
}
const element = browser.$(Selectors.ValidationEditor);
await element.waitForDisplayed();
await browser.setValidationWithinValidationTab(validator);
Expand Down
2 changes: 2 additions & 0 deletions packages/compass-e2e-tests/helpers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,8 @@ export const SavePipelineSaveAsAction =
export const AggregationAutoPreviewToggle =
'[data-testid="pipeline-toolbar-preview-toggle"]';
export const AggregationErrorBanner = '[data-testid="pipeline-results-error"]';
export const AggregationErrorDetailsBtn =
'[data-testid="pipeline-results-error"] [data-testid="pipeline-results-error-details-button"]';

export const RunPipelineButton = `[data-testid="pipeline-toolbar-run-button"]`;
export const EditPipelineButton = `[data-testid="pipeline-toolbar-edit-button"]`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,84 @@ describe('Collection aggregations tab', function () {
);
});

context('with existing validation rule', function () {
const REQUIRE_PHONE_VALIDATOR =
'{ $jsonSchema: { bsonType: "object", required: [ "phone" ] } }';
const VALIDATED_OUT_COLLECTION = 'nestedDocs';
beforeEach(async function () {
await browser.setValidation({
connectionName: DEFAULT_CONNECTION_NAME_1,
database: 'test',
collection: VALIDATED_OUT_COLLECTION,
validator: REQUIRE_PHONE_VALIDATOR,
});
await browser.navigateToCollectionTab(
DEFAULT_CONNECTION_NAME_1,
'test',
'numbers',
'Aggregations'
);
await addStage(browser, 1);
});

afterEach(async function () {
await browser.setValidation({
connectionName: DEFAULT_CONNECTION_NAME_1,
database: 'test',
collection: VALIDATED_OUT_COLLECTION,
validator: '{}',
});
});

it('Shows error info when inserting', async function () {
await browser.selectStageOperator(0, '$out');
await browser.setCodemirrorEditorValue(
Selectors.stageEditor(0),
`'${VALIDATED_OUT_COLLECTION}'`
);

await waitForAnyText(browser, browser.$(Selectors.stageContent(0)));

// run the $out stage
await browser.clickVisible(Selectors.RunPipelineButton);

// confirm the write operation
const writeOperationConfirmationModal = browser.$(
Selectors.AggregationWriteOperationConfirmationModal
);
await writeOperationConfirmationModal.waitForDisplayed();

const description = await browser
.$(Selectors.AggregationWriteOperationConfirmationModalDescription)
.getText();

expect(description).to.contain(`test.${VALIDATED_OUT_COLLECTION}`);

await browser.clickVisible(
Selectors.AggregationWriteOperationConfirmButton
);

await writeOperationConfirmationModal.waitForDisplayed({ reverse: true });

const errorElement = browser.$(Selectors.AggregationErrorBanner);
await errorElement.waitForDisplayed();
expect(await errorElement.getText()).to.include(
'Document failed validation'
);
// enter details
const errorDetailsBtn = browser.$(Selectors.AggregationErrorDetailsBtn);
await errorElement.waitForDisplayed();
await errorDetailsBtn.click();

const errorDetailsJson = browser.$(Selectors.ErrorDetailsJson);
await errorDetailsJson.waitForDisplayed();

// exit details
await browser.clickVisible(Selectors.confirmationModalConfirmButton());
await errorElement.waitForDisplayed();
});
});

it('cancels pipeline with $out as the last stage', async function () {
await browser.selectStageOperator(0, '$out');
await browser.setCodemirrorEditorValue(
Expand Down
Loading