Skip to content

Commit

Permalink
feat(search-indexes): new modal to update search indexes COMPASS-7166 (
Browse files Browse the repository at this point in the history
…#4854)

Co-authored-by: Basit <[email protected]>
  • Loading branch information
kmruiz and mabaasit authored Sep 20, 2023
1 parent 9b1f2d3 commit a23fde8
Show file tree
Hide file tree
Showing 21 changed files with 1,045 additions and 379 deletions.
38 changes: 0 additions & 38 deletions packages/compass-e2e-tests/helpers/commands/create-search-index.ts

This file was deleted.

29 changes: 0 additions & 29 deletions packages/compass-e2e-tests/helpers/commands/drop-search-index.ts

This file was deleted.

2 changes: 0 additions & 2 deletions packages/compass-e2e-tests/helpers/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,3 @@ export * from './create-index';
export * from './drop-index';
export * from './hide-index';
export * from './unhide-index';
export * from './create-search-index';
export * from './drop-search-index';
17 changes: 11 additions & 6 deletions packages/compass-e2e-tests/helpers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -941,17 +941,22 @@ export const indexesSegmentedTab = (name: IndexesType) => {

// Search Index
export const SearchIndexList = '[data-testid="search-indexes"]';
export const CreateSearchIndexModal =
'[data-testid="create-search-index-modal"]';
export const CreateSearchIndexName = '[data-testid="name-of-search-index"]';
export const CreateSearchIndexDefinition =
export const SearchIndexModal = '[data-testid="search-index-modal"]';
export const SearchIndexName = '[data-testid="name-of-search-index"]';
export const SearchIndexDefinition =
'[data-testid="definition-of-search-index"]';
export const CreateSearchIndexConfirmButton =
'[data-testid="create-search-index-button"]';
export const SearchIndexConfirmButton =
'[data-testid="search-index-submit-button"]';
export const searchIndexRow = (name: string) =>
`[data-testid="search-indexes-row-${name}"]`;
export const searchIndexExpandButton = (name: string) =>
`${searchIndexRow(name)} button:first-child`;
export const searchIndexDropButton = (name: string) =>
`${searchIndexRow(name)} [data-testid="search-index-actions-drop-action"]`;
export const searchIndexEditButton = (name: string) =>
`${searchIndexRow(name)} [data-testid="search-index-actions-edit-action"]`;
export const searchIndexDetails = (name: string) =>
`[data-testid="search-indexes-details-${name}"]`;

// Indexes modal
export const CreateIndexModal = '[data-testid="create-index-modal"]';
Expand Down
135 changes: 124 additions & 11 deletions packages/compass-e2e-tests/tests/search-indexes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,92 @@ function getRandomNumber() {
return Math.floor(Math.random() * 2 ** 20);
}

async function createSearchIndex(
browser: CompassBrowser,
indexName: string,
indexDefinition: string
): Promise<void> {
await browser.clickVisible(Selectors.CreateIndexDropdownButton);
await browser
.$(Selectors.createIndexDropdownAction('search-indexes'))
.waitForDisplayed();
await browser.clickVisible(
Selectors.createIndexDropdownAction('search-indexes')
);

const modal = await browser.$(Selectors.SearchIndexModal);
await modal.waitForDisplayed();

await browser.setValueVisible(Selectors.SearchIndexName, indexName);
await browser.setCodemirrorEditorValue(
Selectors.SearchIndexDefinition,
indexDefinition
);

await browser.clickVisible(Selectors.SearchIndexConfirmButton);
await modal.waitForDisplayed({ reverse: true });
}

async function updateSearchIndex(
browser: CompassBrowser,
indexName: string,
indexDefinition: string
) {
const indexRowSelector = Selectors.searchIndexRow(indexName);
const indexRow = await browser.$(indexRowSelector);
await indexRow.waitForDisplayed();

await browser.hover(indexRowSelector);
await browser.clickVisible(Selectors.searchIndexEditButton(indexName));

const modal = await browser.$(Selectors.SearchIndexModal);
await modal.waitForDisplayed();

await browser.setCodemirrorEditorValue(
Selectors.SearchIndexDefinition,
indexDefinition
);

await browser.clickVisible(Selectors.SearchIndexConfirmButton);
await modal.waitForDisplayed({ reverse: true });
}

async function dropSearchIndex(browser: CompassBrowser, indexName: string) {
const indexRowSelector = Selectors.searchIndexRow(indexName);
const indexRow = await browser.$(indexRowSelector);
await indexRow.waitForDisplayed();

await browser.hover(indexRowSelector);
await browser.clickVisible(Selectors.searchIndexDropButton(indexName));

const modal = await browser.$(Selectors.ConfirmationModal);
await modal.waitForDisplayed();

const confirmInput = await browser.$(Selectors.ConfirmationModalInput);
await confirmInput.waitForDisplayed();
await confirmInput.setValue(indexName);

await browser.clickVisible(Selectors.ConfirmationModalConfirmButton());
await modal.waitForDisplayed({ reverse: true });
}

async function verifyIndexDetails(
browser: CompassBrowser,
indexName: string,
details: string
) {
const indexRowSelector = Selectors.searchIndexRow(indexName);
const indexRow = await browser.$(indexRowSelector);
await indexRow.waitForDisplayed();
await browser.hover(indexRowSelector);
await browser.clickVisible(Selectors.searchIndexExpandButton(indexName));

const text = await browser
.$(Selectors.searchIndexDetails(indexName))
.getText();
expect(text.toLowerCase()).to.equal(details.toLowerCase());
}

describe('Search Indexes', function () {
let compass: Compass;
let browser: CompassBrowser;
Expand Down Expand Up @@ -161,24 +247,51 @@ describe('Search Indexes', function () {
await browser.clickVisible(
Selectors.indexesSegmentedTab('search-indexes')
);
await browser.createSearchIndex(indexName, INDEX_DEFINITION);
await createSearchIndex(browser, indexName, INDEX_DEFINITION);
await browser.waitForAnimations(Selectors.SearchIndexList);

const rowSelector = Selectors.searchIndexRow(indexName);

// View it
await browser.$(rowSelector).waitForDisplayed();
await browser.waitUntil(async function () {
const text = await browser.$(rowSelector).getText();
return text.indexOf('PENDING') > -1;
});
// Verify it was added.
// As we added index definition with no fields and only
// dynamic mapping, the details should display 'Dynamic Mappings'
await verifyIndexDetails(browser, indexName, 'Dynamic Mappings');

// Drop it
await browser.dropSearchIndex(indexName);
await dropSearchIndex(browser, indexName);
// todo: check the index status to be either DELETING or the row disappears
});

it('allows users to update and view search indexes');
it('allows users to update and view search indexes', async function () {
const indexName = `e2e_search_index_${getRandomNumber()}`;
await browser.clickVisible(
Selectors.indexesSegmentedTab('search-indexes')
);
await createSearchIndex(browser, indexName, INDEX_DEFINITION);
await browser.waitForAnimations(Selectors.SearchIndexList);

// Verify it was added.
// As we added index definition with no fields and only
// dynamic mapping, the details should display 'Dynamic Mappings'
await verifyIndexDetails(browser, indexName, 'Dynamic Mappings');

// Edit it
await updateSearchIndex(
browser,
indexName,
JSON.stringify({
mappings: {
dynamic: false,
},
})
);

// Verify its updating/updated.
// As we set the new definition to have no dynamic mappings
// with no fields, the index details should have '[empty]' value.
await verifyIndexDetails(browser, indexName, '[empty]');

// Drop it
await dropSearchIndex(browser, indexName);
});
it('runs a search aggregation with index name');
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const renderIndexes = (props: Partial<typeof Store> = {}) => {
createIndex: {
isModalOpen: false,
},
updateIndex: {
isModalOpen: false,
},
},
...props,
};
Expand Down
8 changes: 6 additions & 2 deletions packages/compass-indexes/src/components/indexes/indexes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import RegularIndexesTable from '../regular-indexes-table/regular-indexes-table'
import SearchIndexesTable from '../search-indexes-table/search-indexes-table';
import { refreshRegularIndexes } from '../../modules/regular-indexes';
import {
openModalForCreation as openAtlasSearchModalForCreation,
showCreateModal as openAtlasSearchModalForCreation,
refreshSearchIndexes,
} from '../../modules/search-indexes';
import type { State as RegularIndexesState } from '../../modules/regular-indexes';
import type { State as SearchIndexesState } from '../../modules/search-indexes';
import { SearchIndexesStatuses } from '../../modules/search-indexes';
import type { SearchIndexesStatus } from '../../modules/search-indexes';
import type { RootState } from '../../modules';
import { CreateSearchIndexModal } from '../search-indexes-modals';
import {
CreateSearchIndexModal,
UpdateSearchIndexModal,
} from '../search-indexes-modals';

// This constant is used as a trigger to show an insight whenever number of
// indexes in a collection is more than what is specified here.
Expand Down Expand Up @@ -116,6 +119,7 @@ export function Indexes({
<SearchIndexesTable />
)}
<CreateSearchIndexModal />
<UpdateSearchIndexModal />
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { expect } from 'chai';
import { BaseSearchIndexModal } from './base-search-index-modal';
import sinon from 'sinon';
import type { SinonSpy } from 'sinon';

import { render, screen, cleanup } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import React from 'react';
import { getCodemirrorEditorValue } from '@mongodb-js/compass-editor';

describe('Create Search Index Modal', function () {
let onSubmitSpy: SinonSpy;
let onCloseSpy: SinonSpy;

beforeEach(function () {
onSubmitSpy = sinon.spy();
onCloseSpy = sinon.spy();

render(
<BaseSearchIndexModal
mode="create"
initialIndexName={'default'}
initialIndexDefinition={'{}'}
isModalOpen={true}
isBusy={false}
onSubmit={onSubmitSpy}
onClose={onCloseSpy}
error={'Invalid index definition.'}
/>
);
});

afterEach(cleanup);

describe('default behaviour', function () {
it('uses the initial index name as the default index name', function () {
const inputText: HTMLInputElement = screen.getByTestId(
'name-of-search-index'
);

expect(inputText).to.not.be.null;
expect(inputText?.value).to.equal('default');
});

it('uses a dynamic mapping as the default index definition', function () {
const defaultIndexDef = getCodemirrorEditorValue(
'definition-of-search-index'
);

expect(defaultIndexDef).to.not.be.null;
expect(defaultIndexDef).to.equal('{}');
});
});

describe('form validation', function () {
it('shows an error when the index name is empty', async function () {
const inputText: HTMLInputElement = screen.getByTestId(
'name-of-search-index'
);

userEvent.clear(inputText);
expect(await screen.findByText('Please enter the name of the index.')).to
.exist;
});

it('shows server errors', async function () {
expect(await screen.findByText('Invalid index definition.')).to.exist;
});
});

describe('form behaviour', function () {
it('closes the modal on cancel', function () {
const cancelButton: HTMLButtonElement = screen
.getByText('Cancel')
.closest('button')!;

userEvent.click(cancelButton);
expect(onCloseSpy).to.have.been.calledOnce;
});

it('submits the modal on create search index', function () {
const submitButton: HTMLButtonElement = screen
.getByTestId('search-index-submit-button')
.closest('button')!;

userEvent.click(submitButton);
expect(onSubmitSpy).to.have.been.calledOnceWithExactly('default', {});
});
});
});
Loading

0 comments on commit a23fde8

Please sign in to comment.