Skip to content

Commit 3b38924

Browse files
authored
test(focus-mode): add e2e tests COMPASS-6473 (#4038)
1 parent 7bfb579 commit 3b38924

File tree

4 files changed

+254
-7
lines changed

4 files changed

+254
-7
lines changed

packages/compass-aggregations/src/components/focus-mode/focus-mode-modal-header.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export const FocusModeModalHeader: React.FunctionComponent<
162162
size="xsmall"
163163
disabled={isFirst}
164164
onClick={onPreviousStage}
165+
data-testid="previous-stage-button"
165166
aria-label="Edit previous stage"
166167
>
167168
<Icon
@@ -183,6 +184,7 @@ export const FocusModeModalHeader: React.FunctionComponent<
183184
</Tooltip>
184185
{/* @ts-expect-error leafygreen unresonably expects a labelledby here */}
185186
<Select
187+
data-testid="stage-select"
186188
allowDeselect={false}
187189
style={stageSelectStyle}
188190
size="xsmall"
@@ -211,6 +213,7 @@ export const FocusModeModalHeader: React.FunctionComponent<
211213
disabled={isLast}
212214
onClick={onNextStage}
213215
aria-label="Edit next stage"
216+
data-testid="next-stage-button"
214217
>
215218
<Icon
216219
size="xsmall"
@@ -244,13 +247,15 @@ export const FocusModeModalHeader: React.FunctionComponent<
244247
</div>
245248

246249
<Menu
250+
data-testid="add-stage-menu-content"
247251
className={menuStyles}
248252
open={menuOpen}
249253
setOpen={setMenuOpen}
250254
trigger={({ onClick, children }: any) => {
251255
return (
252256
<div className={controlContainerStyles}>
253257
<Button
258+
data-testid="add-stage-menu-button"
254259
size="xsmall"
255260
leftGlyph={
256261
<Icon

packages/compass-aggregations/src/components/stage-toolbar/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ export function StageToolbar({
135135
<IconButton
136136
onClick={() => onFocusModeEnableClick(index)}
137137
aria-label="Open stage in focus mode"
138+
data-testid="focus-mode-button"
138139
>
139140
<Icon glyph="FullScreenEnter" size="small"></Icon>
140141
</IconButton>

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,9 @@ export const stageCollapseButton = (stageIndex: number): string => {
766766
export const stageExpandButton = (stageIndex: number): string => {
767767
return `[data-stage-index="${stageIndex}"] button[title="Expand"]`;
768768
};
769+
export const stageFocusModeButton = (stageIndex: number): string => {
770+
return `[data-stage-index="${stageIndex}"] [data-testid="focus-mode-button"]`;
771+
};
769772
export const stagePickerComboboxInput = (stageIndex: number): string => {
770773
return `[data-stage-index="${stageIndex}"] [data-testid="stage-operator-combobox"] [role="combobox"] input`;
771774
};
@@ -791,6 +794,19 @@ export const StageMoreOptionsContent = `[data-testid="stage-option-menu-content"
791794

792795
export const StageDelete = `[data-testid="stage-option-menu-content"] [data-text="Delete stage"]`;
793796

797+
// Focus Mode
798+
export const FocusModeModal = '[data-testid="focus-mode-modal"]';
799+
export const FocusModeStageInput = `${FocusModeModal} [data-testid="stage-input"]`;
800+
export const FocusModeStageEditor = `${FocusModeModal} [data-testid="stage-editor"]`;
801+
export const FocusModeStageOutput = `${FocusModeModal} [data-testid="stage-output"]`;
802+
export const FocusModeCloseModalButton = `${FocusModeModal} [aria-label="Close modal"]`;
803+
export const FocusModePreviousStageButton = `${FocusModeModal} [data-testid="previous-stage-button"]`;
804+
export const FocusModeNextStageButton = `${FocusModeModal} [data-testid="next-stage-button"]`;
805+
export const FocusModeActiveStageLabel = `${FocusModeModal} [data-testid="stage-select"]`;
806+
export const FocusModeAddStageMenuButton = `${FocusModeModal} [data-testid="add-stage-menu-button"]`;
807+
export const FocusModeAddStageBeforeMenuItem = `[data-testid="add-stage-menu-content"] [data-text="Add stage before"]`;
808+
export const FocusModeAddStageAfterMenuItem = `[data-testid="add-stage-menu-content"] [data-text="Add stage after"]`;
809+
794810
export const stageEditorErrorMessage = (stageIndex: number): string => {
795811
return `[data-stage-index="${stageIndex}"] [data-testid="stage-editor-error-message"]`;
796812
};

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

Lines changed: 232 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ import { getStageOperators } from '../helpers/read-stage-operators';
1616

1717
const { expect } = chai;
1818

19+
const OUT_STAGE_PREVIEW_TEXT =
20+
'The $out operator will cause the pipeline to persist the results to the specified location (collection, S3, or Atlas). If the collection exists it will be replaced.';
21+
const MERGE_STAGE_PREVIEW_TEXT =
22+
'The $merge operator will cause the pipeline to persist the results to the specified location.';
23+
1924
async function waitForAnyText(
2025
browser: CompassBrowser,
2126
element: Element<'async'>
@@ -180,7 +185,9 @@ describe('Collection aggregations tab', function () {
180185
let browser: CompassBrowser;
181186

182187
before(async function () {
183-
compass = await beforeTests();
188+
compass = await beforeTests({
189+
extraSpawnArgs: ['--show-focus-mode'],
190+
});
184191
browser = compass.browser;
185192
});
186193

@@ -308,9 +315,7 @@ describe('Collection aggregations tab', function () {
308315
const text = await preview.getText();
309316

310317
expect(text).to.include('Documents will be saved to test.listings.');
311-
expect(text).to.include(
312-
'The $out operator will cause the pipeline to persist the results to the specified location (collection, S3, or Atlas). If the collection exists it will be replaced.'
313-
);
318+
expect(text).to.include(OUT_STAGE_PREVIEW_TEXT);
314319
});
315320

316321
it('shows $merge stage preview', async function () {
@@ -326,9 +331,7 @@ describe('Collection aggregations tab', function () {
326331
const text = await preview.getText();
327332

328333
expect(text).to.include('Documents will be saved to test.listings.');
329-
expect(text).to.include(
330-
'The $merge operator will cause the pipeline to persist the results to the specified location.'
331-
);
334+
expect(text).to.include(MERGE_STAGE_PREVIEW_TEXT);
332335
});
333336

334337
it('shows empty preview', async function () {
@@ -1093,6 +1096,228 @@ describe('Collection aggregations tab', function () {
10931096
});
10941097
});
10951098

1099+
describe('focus mode', function () {
1100+
it('opens and closes the modal', async function () {
1101+
await browser.selectStageOperator(0, '$match');
1102+
await browser.setAceValue(Selectors.stageEditor(0), '{ i: 5 }');
1103+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1104+
const modal = await browser.$(Selectors.FocusModeModal);
1105+
await modal.waitForDisplayed();
1106+
1107+
await browser.$(Selectors.FocusModeStageInput).waitForDisplayed();
1108+
await browser.$(Selectors.FocusModeStageEditor).waitForDisplayed();
1109+
await browser.$(Selectors.FocusModeStageOutput).waitForDisplayed();
1110+
1111+
const closeButton = await browser.$(Selectors.FocusModeCloseModalButton);
1112+
await closeButton.click();
1113+
1114+
await modal.waitForDisplayed({ reverse: true });
1115+
});
1116+
1117+
it('navigates between stages', async function () {
1118+
await browser.selectStageOperator(0, '$match');
1119+
await browser.setAceValue(Selectors.stageEditor(0), '{ i: 5 }');
1120+
1121+
await browser.clickVisible(Selectors.AddStageButton);
1122+
await browser.$(Selectors.stageEditor(1)).waitForDisplayed();
1123+
await browser.selectStageOperator(1, '$limit');
1124+
await browser.setAceValue(Selectors.stageEditor(1), '10');
1125+
1126+
await browser.clickVisible(Selectors.AddStageButton);
1127+
await browser.$(Selectors.stageEditor(2)).waitForDisplayed();
1128+
await browser.selectStageOperator(2, '$sort');
1129+
await browser.setAceValue(Selectors.stageEditor(2), '{ i: -1 }');
1130+
1131+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1132+
const modal = await browser.$(Selectors.FocusModeModal);
1133+
await modal.waitForDisplayed();
1134+
1135+
const nextButton = await browser.$(Selectors.FocusModeNextStageButton);
1136+
const previousButton = await browser.$(
1137+
Selectors.FocusModePreviousStageButton
1138+
);
1139+
1140+
await nextButton.waitForDisplayed();
1141+
await previousButton.waitForDisplayed();
1142+
1143+
expect(await previousButton.isEnabled()).to.equal(false);
1144+
1145+
await browser.waitUntil(async () => {
1146+
const activeStage = await browser.$(
1147+
Selectors.FocusModeActiveStageLabel
1148+
);
1149+
return (await activeStage.getText()) === 'Stage 1: $match';
1150+
});
1151+
1152+
await nextButton.click();
1153+
await browser.waitUntil(async () => {
1154+
const activeStage = await browser.$(
1155+
Selectors.FocusModeActiveStageLabel
1156+
);
1157+
return (await activeStage.getText()) === 'Stage 2: $limit';
1158+
});
1159+
1160+
await nextButton.click();
1161+
await browser.waitUntil(async () => {
1162+
const activeStage = await browser.$(
1163+
Selectors.FocusModeActiveStageLabel
1164+
);
1165+
return (await activeStage.getText()) === 'Stage 3: $sort';
1166+
});
1167+
1168+
expect(await nextButton.isEnabled()).to.equal(false);
1169+
1170+
await previousButton.click();
1171+
await browser.waitUntil(async () => {
1172+
const activeStage = await browser.$(
1173+
Selectors.FocusModeActiveStageLabel
1174+
);
1175+
return (await activeStage.getText()) === 'Stage 2: $limit';
1176+
});
1177+
1178+
await previousButton.click();
1179+
await browser.waitUntil(async () => {
1180+
const activeStage = await browser.$(
1181+
Selectors.FocusModeActiveStageLabel
1182+
);
1183+
return (await activeStage.getText()) === 'Stage 1: $match';
1184+
});
1185+
1186+
expect(await previousButton.isEnabled()).to.equal(false);
1187+
1188+
await browser.keys('Escape');
1189+
await modal.waitForDisplayed({ reverse: true });
1190+
});
1191+
1192+
it('adds a new stage before or after current stage', async function () {
1193+
await browser.selectStageOperator(0, '$match');
1194+
await browser.setAceValue(Selectors.stageEditor(0), '{ i: 5 }');
1195+
1196+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1197+
const modal = await browser.$(Selectors.FocusModeModal);
1198+
await modal.waitForDisplayed();
1199+
1200+
await browser.waitUntil(async () => {
1201+
const activeStage = await browser.$(
1202+
Selectors.FocusModeActiveStageLabel
1203+
);
1204+
return (await activeStage.getText()) === 'Stage 1: $match';
1205+
});
1206+
1207+
const addStageMenu = await browser.$(
1208+
Selectors.FocusModeAddStageMenuButton
1209+
);
1210+
await addStageMenu.waitForDisplayed();
1211+
1212+
// Add a stage before the current stage.
1213+
await addStageMenu.click();
1214+
1215+
const addStageBeforeButton = await browser.$(
1216+
Selectors.FocusModeAddStageBeforeMenuItem
1217+
);
1218+
await addStageBeforeButton.waitForDisplayed();
1219+
await addStageBeforeButton.click();
1220+
1221+
await browser.waitUntil(async () => {
1222+
const labelElem = await browser.$(Selectors.FocusModeActiveStageLabel);
1223+
return (await labelElem.getText()) === 'Stage 1: select';
1224+
});
1225+
1226+
// Add a stage after the current stage.
1227+
await addStageMenu.click();
1228+
1229+
const addStageAfterButton = await browser.$(
1230+
Selectors.FocusModeAddStageAfterMenuItem
1231+
);
1232+
await addStageAfterButton.waitForDisplayed();
1233+
await addStageAfterButton.click();
1234+
1235+
await browser.waitUntil(async () => {
1236+
const activeStage = await browser.$(
1237+
Selectors.FocusModeActiveStageLabel
1238+
);
1239+
return (await activeStage.getText()) === 'Stage 2: select';
1240+
});
1241+
1242+
await browser.keys('Escape');
1243+
await modal.waitForDisplayed({ reverse: true });
1244+
});
1245+
1246+
it('hides stage input and output when preview is disabled', async function () {
1247+
await browser.clickVisible(Selectors.AggregationAutoPreviewToggle);
1248+
1249+
await browser.selectStageOperator(0, '$match');
1250+
await browser.setAceValue(Selectors.stageEditor(0), '{ i: 5 }');
1251+
1252+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1253+
const modal = await browser.$(Selectors.FocusModeModal);
1254+
await modal.waitForDisplayed();
1255+
1256+
await browser
1257+
.$(Selectors.FocusModeStageInput)
1258+
.waitForDisplayed({ reverse: true });
1259+
await browser.$(Selectors.FocusModeStageEditor).waitForDisplayed();
1260+
await browser
1261+
.$(Selectors.FocusModeStageOutput)
1262+
.waitForDisplayed({ reverse: true });
1263+
});
1264+
1265+
it('handles $out stage operators', async function () {
1266+
await browser.selectStageOperator(0, '$out');
1267+
await browser.setAceValue(Selectors.stageEditor(0), '"test"');
1268+
1269+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1270+
const modal = await browser.$(Selectors.FocusModeModal);
1271+
await modal.waitForDisplayed();
1272+
1273+
await browser.waitUntil(async () => {
1274+
const outputElem = await browser.$(Selectors.FocusModeStageOutput);
1275+
const text = await outputElem.getText();
1276+
return text.includes(OUT_STAGE_PREVIEW_TEXT);
1277+
});
1278+
});
1279+
1280+
it('handles $merge stage operators', async function () {
1281+
if (serverSatisfies('< 4.2.0')) {
1282+
return this.skip();
1283+
}
1284+
1285+
await browser.selectStageOperator(0, '$merge');
1286+
await browser.setAceValue(Selectors.stageEditor(0), '"test"');
1287+
1288+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1289+
const modal = await browser.$(Selectors.FocusModeModal);
1290+
await modal.waitForDisplayed();
1291+
1292+
await browser.waitUntil(async () => {
1293+
const outputElem = await browser.$(Selectors.FocusModeStageOutput);
1294+
const text = await outputElem.getText();
1295+
return text.includes(MERGE_STAGE_PREVIEW_TEXT);
1296+
});
1297+
});
1298+
1299+
it('handles atlas only operator', async function () {
1300+
if (serverSatisfies('< 4.1.11')) {
1301+
this.skip();
1302+
}
1303+
1304+
await browser.selectStageOperator(0, '$search');
1305+
await browser.setAceValue(Selectors.stageEditor(0), '{}');
1306+
1307+
await browser.clickVisible(Selectors.stageFocusModeButton(0));
1308+
const modal = await browser.$(Selectors.FocusModeModal);
1309+
await modal.waitForDisplayed();
1310+
1311+
await browser.waitUntil(async () => {
1312+
const outputElem = await browser.$(Selectors.FocusModeStageOutput);
1313+
const text = await outputElem.getText();
1314+
return text.includes(
1315+
'The $search stage is only available with MongoDB Atlas.'
1316+
);
1317+
});
1318+
});
1319+
});
1320+
10961321
// TODO: stages can be re-arranged by drag and drop and the preview is refreshed after rearranging them
10971322
// TODO: test auto-preview and limit
10981323
// TODO: save a pipeline, close compass, re-open compass, load the pipeline

0 commit comments

Comments
 (0)