import React from 'react';
import Sinon from 'sinon';
import {
render,
screen,
cleanup,
within,
waitFor,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect } from 'chai';
import { queries, pipelines, DATE } from '../test/fixtures';
import { MyQueriesPlugin } from '.';
describe('AggregationsQueriesList', function () {
const sandbox = Sinon.createSandbox();
const dataService = {} as any;
const instance = {} as any;
const queryStorage = {
loadAll: sandbox.stub().resolves([]),
updateAttributes: sandbox.stub().resolves({}),
};
const pipelineStorage = {
loadAll: sandbox.stub().resolves([]),
updateAttributes: sandbox.stub().resolves({}),
};
const Plugin = MyQueriesPlugin.withMockServices({
dataService,
instance,
queryStorage,
pipelineStorage,
});
afterEach(function () {
sandbox.resetHistory();
cleanup();
});
it('should display no saved items when user has no saved queries/aggregations', async function () {
render();
expect(await screen.findByText('No saved queries yet.')).to.exist;
});
it('should load queries and display them in the list', async function () {
queryStorage.loadAll.resolves([
{
_id: '123',
_name: 'Query',
_ns: 'bar.foo',
_dateSaved: DATE,
},
]);
render();
expect(await screen.findByText('Query')).to.exist;
});
it('should load aggregations and display them in the list', async function () {
queryStorage.loadAll.resolves([]);
pipelineStorage.loadAll.resolves([
{
id: '123',
name: 'Aggregation',
namespace: 'foo.bar',
lastModified: 0,
},
]);
render();
expect(await screen.findByText('Aggregation')).to.exist;
});
describe('copy to clipboard', function () {
it('should copy query to the clipboard', async function () {
queryStorage.loadAll.resolves([
{
_id: '123',
_name: 'My Query',
_ns: 'bar.foo',
_dateSaved: DATE,
filter: { foo: 'bar' },
sort: { bar: -1 },
},
]);
pipelineStorage.loadAll.resolves([]);
render();
await waitFor(async () => await screen.findByText('My Query'));
const card = await screen.findByRole('gridcell');
userEvent.hover(card);
userEvent.click(within(card).getByLabelText(/show actions/i));
userEvent.click(within(card).getByText('Copy'));
expect(await navigator.clipboard.readText()).to.eq(`{
"collation": null,
"filter": {
"foo": "bar"
},
"limit": null,
"project": null,
"skip": null,
"sort": {
"bar": -1
}
}`);
});
it('should copy aggregation to the clipboard', async function () {
queryStorage.loadAll.resolves([]);
pipelineStorage.loadAll.resolves([
{
id: '123',
name: 'My Aggregation',
namespace: 'foo.bar',
lastModified: 0,
pipelineText: `[
{
$match: {
"field": 42
}
}
]`,
},
]);
render();
await waitFor(async () => await screen.findByText('My Aggregation'));
const card = await screen.findByRole('gridcell');
userEvent.hover(card);
userEvent.click(within(card).getByLabelText(/show actions/i));
userEvent.click(within(card).getByText('Copy'));
expect(await navigator.clipboard.readText()).to.eq(`[
{
$match: {
"field": 42
}
}
]`);
});
});
context('with fixtures', function () {
beforeEach(async function () {
queryStorage.loadAll.resolves(queries.map((item) => item.query));
pipelineStorage.loadAll.resolves(
pipelines.map((item) => item.aggregation)
);
render();
// Wait for the items to "load"
await screen.findByText(queries[0].name);
});
it('should filter items by database/collection', function () {
const { database, collection } = queries[0];
// select database
userEvent.click(screen.getByRole('button', { name: 'All databases' }));
userEvent.click(screen.getByRole('option', { name: database }));
// select collection
userEvent.click(screen.getByRole('button', { name: 'All collections' }));
userEvent.click(screen.getByRole('option', { name: collection }));
const expectedItems = [...queries, ...pipelines].filter(
(item) => item.database === database && item.collection === collection
);
expectedItems.forEach((item) => {
expect(screen.getByText(item.name)).to.exist;
});
});
it('should rename an item', async function () {
const item = queries[0];
const updatedName = 'the updated name';
// The first item is a query, so we are mocking that
queryStorage.updateAttributes.resolves({
...item.query,
_name: updatedName,
});
const card = document.querySelector(
`[data-id="${item.id}"]`
);
if (!card) {
throw new Error('Expected card to exist');
}
userEvent.hover(card);
userEvent.click(within(card).getByLabelText('Show actions'));
userEvent.click(within(card).getByText('Rename'));
const modal = screen.getByTestId('edit-item-modal');
const title = new RegExp('rename query', 'i');
expect(within(modal).getByText(title), 'show title').to.exist;
const nameInput = within(modal).getByRole('textbox', {
name: /name/i,
});
expect(nameInput, 'show name input').to.exist;
expect(nameInput, 'input with item name').to.have.property(
'value',
item.name
);
expect(
within(modal).getByRole('button', {
name: /update/i,
}).disabled,
'submit button is disabled when user has not changed field value'
).to.be.true;
userEvent.clear(nameInput);
expect(
within(modal).getByRole('button', {
name: /update/i,
}).disabled,
'submit button is disabled when field value is empty'
).to.be.true;
userEvent.type(nameInput, updatedName);
userEvent.click(
within(modal).getByRole('button', {
name: /update/i,
})
);
await waitFor(() => {
expect(screen.queryByText(item.name)).to.not.exist;
expect(screen.getByText(updatedName)).to.exist;
});
});
it('should not update an item if rename was not confirmed', async function () {
const item = queries[0];
const card = document.querySelector(
`[data-id="${item.id}"]`
);
if (!card) {
throw new Error('Expected card to exist');
}
userEvent.hover(card);
userEvent.click(within(card).getByLabelText('Show actions'));
userEvent.click(within(card).getByText('Rename'));
const modal = await screen.findByTestId('edit-item-modal');
userEvent.click(within(modal).getByText('Cancel'), undefined, {
skipPointerEventsCheck: true,
});
expect(screen.queryByText(item.name)).to.exist;
});
});
});