blob: 805a32d00c4c4c0b2a5a23e2f02a9f80ffb97974 [file] [log] [blame]
import './index';
import { setUpElementUnderTest, eventPromise, noEventPromise } from '../../../infra-sk/modules/test_util';
import { QueryDialogSk } from './query-dialog-sk';
import { ParamSet, fromParamSet } from 'common-sk/modules/query';
import { $, $$ } from 'common-sk/modules/dom';
const expect = chai.expect;
describe('query-dialog-sk', () => {
const newInstance = setUpElementUnderTest<QueryDialogSk>('query-dialog-sk');
let queryDialogSk: QueryDialogSk;
beforeEach(() => {
queryDialogSk = newInstance();
});
describe('open/close/edit events', () => {
it('should emit "query-dialog-open" when opened', async () => {
const event = eventPromise('query-dialog-open');
queryDialogSk.open({}, '');
await event;
});
it('should emit "query-dialog-close" but not "edit" when closed via the "Cancel" button',
async () => {
queryDialogSk.open({}, '');
const events = Promise.all([eventPromise('query-dialog-close'), noEventPromise('edit')]);
clickCancelBtn();
await events;
});
it('should emit "query-dialog-close" and "edit" when closed via the "Show Matches" button',
async () => {
queryDialogSk.open({}, '');
const events = Promise.all([eventPromise('query-dialog-close'), eventPromise('edit')]);
clickShowMatchesBtn();
await events;
});
})
describe('opened with an empty selection', () => {
const paramSet: ParamSet = {'a': ['1', '2', '3'], 'b': ['4', '5'], 'c': ['6']};
beforeEach(() => {
queryDialogSk.open(paramSet, /* selection= */ '');
});
it('should have an empty selection', () => {
// The query-sk component correctly shows the ParamSet.
expect(querySkContents()).to.deep.equal(paramSet);
// But none of the ParamSet items are selected.
expect(querySkSelection()).to.deep.equal({});
// The "empty selection" placeholder text is visible instead of the paramset-sk component.
expect(isEmptySelectionPlaceholderTextVisible()).to.be.true;
expect(isParamSetSkVisible()).to.be.false;
});
it('should update paramset-sk when selection changes', async () => {
// Select a=1.
clickQuerySkKey('a');
clickQuerySkValue('1');
expect(querySkSelection()).to.deep.equal({'a': ['1']});
expect(paramSetSkContents()).to.deep.equal({'a': ['1']});
// The placeholder text should not be visible. It suffices to assert this just once.
expect(isEmptySelectionPlaceholderTextVisible()).to.be.false;
// Select a=2.
clickQuerySkValue('2');
expect(querySkSelection()).to.deep.equal({'a': ['1', '2']});
expect(paramSetSkContents()).to.deep.equal({'a': ['1', '2']});
// Select b=4.
clickQuerySkKey('b');
clickQuerySkValue('4', );
expect(querySkSelection()).to.deep.equal({'a': ['1', '2'], 'b': ['4']});
expect(paramSetSkContents()).to.deep.equal({'a': ['1', '2'], 'b': ['4']});
});
it('should emit event "edit" containing the current selection when "Show Matches" is clicked',
async () => {
// Select a=1.
clickQuerySkKey('a');
clickQuerySkValue('1');
// Select a=2.
clickQuerySkValue('2');
// Select b=4.
clickQuerySkKey('b');
clickQuerySkValue('4', );
// Click "Show Matches" button and catch the "edit" event.
const event = eventPromise<CustomEvent<string>>('edit');
clickShowMatchesBtn();
const eventSelection = (await event).detail;
// The event contents should match the selection.
expect(eventSelection).to.equal('a=1&a=2&b=4');
});
it('should clear the previous selection when reopened with an empty selection', async () => {
// Select a=1.
clickQuerySkKey('a');
clickQuerySkValue('1');
// It should have selected a=1.
expect(querySkSelection()).to.deep.equal({'a': ['1']});
expect(paramSetSkContents()).to.deep.equal({'a': ['1']});
// Close dialog.
clickShowMatchesBtn();
// Reopen with same ParamSet and empty selection.
queryDialogSk.open(paramSet, /* selection= */ '');
// Selection should be empty.
expect(querySkSelection()).to.deep.equal({});
expect(paramSetSkContents()).to.deep.equal({});
});
})
describe('opened with a non-empty selection', () => {
const paramSet: ParamSet = {'a': ['1', '2', '3'], 'b': ['4', '5'], 'c': ['6']};
const selection: ParamSet = {'a': ['1', '2'], 'b': ['4']};
beforeEach(() => {
queryDialogSk.open(paramSet, fromParamSet(selection));
});
it('shows the passed in selection', () => {
// Both query-sk and paramset-sk show the passed in selection.
expect(querySkSelection()).to.deep.equal(selection);
expect(paramSetSkContents()).to.deep.equal(selection);
// The "empty selection" placeholder text is not visible.
expect(isEmptySelectionPlaceholderTextVisible()).to.be.false;
});
it('can be reopened with a different selection', () => {
const differentSelection: ParamSet = {'a': ['2', '3'], 'c': ['6']};
// Close dialog and reopen it with a different selection.
clickCancelBtn();
queryDialogSk.open(paramSet, fromParamSet(differentSelection));
// Both query-sk and paramset-sk show the passed in selection.
expect(querySkSelection()).to.deep.equal(differentSelection);
expect(paramSetSkContents()).to.deep.equal(differentSelection);
});
});
describe('reopened with a different ParamSet', () => {
const paramSet: ParamSet = {'a': ['1', '2', '3'], 'b': ['4', '5'], 'c': ['6']};
const selection: ParamSet = {'a': ['3'], 'b': ['4']};
const differentParamSet: ParamSet = {'a': ['3', '4', '5'], 'b': ['6'], 'z': ['7']};
const differentSelection: ParamSet = {'a': ['3', '4'], 'b': ['6']};
beforeEach(() => {
queryDialogSk.open(paramSet, fromParamSet(selection));
})
it('can be reopened with a different ParamSet and an empty selection', () => {
// Close dialog and reopen it with a different ParamSet.
clickCancelBtn();
queryDialogSk.open(differentParamSet, /* selection= */ '');
// The query-sk component shows the new ParamSet, and the selection is empty.
expect(querySkContents()).to.deep.equal(differentParamSet);
expect(querySkSelection()).to.deep.equal({});
// The "empty selection" placeholder text is visible instead of the paramset-sk component.
expect(isEmptySelectionPlaceholderTextVisible()).to.be.true;
expect(isParamSetSkVisible()).to.be.false;
});
it('can be reopened with a different ParamSet and a non-empty selection', () => {
// Close dialog and reopen it with a different ParamSet and a non-empty selection.
clickCancelBtn();
queryDialogSk.open(differentParamSet, fromParamSet(differentSelection));
// Both query-sk and paramset-sk show the passed in selection.
expect(querySkSelection()).to.deep.equal(differentSelection);
expect(paramSetSkContents()).to.deep.equal(differentSelection);
// The placeholder text should not be visible.
expect(isEmptySelectionPlaceholderTextVisible()).to.be.false;
});
});
it('rationalizes an invalid selection', () => {
const paramSet: ParamSet = {'a': ['1', '2', '3'], 'b': ['4', '5'], 'c': ['6']};
// This contains the invalid value "a=4" and a value for the invalid key "d".
const invalidSelection: ParamSet = {'a': ['2', '3', '4'], 'b': ['5'], 'd': ['7']};
// This is the invalidSelection with the invalid key/value pairs removed.
const rationalizedSelection: ParamSet = {'a': ['2', '3'], 'b': ['5']};
// Open dialog with invalid selection.
queryDialogSk.open(paramSet, fromParamSet(invalidSelection));
// The dialog should rationalize the invalid selection.
expect(querySkSelection()).to.deep.equal(rationalizedSelection);
expect(paramSetSkContents()).to.deep.equal(rationalizedSelection);
});
it('can customize the submit button label', () => {
// Dialog contents do not matter.
queryDialogSk.open({'a': ['1']}, '');
const showMatchesBtn = $$<HTMLButtonElement>('button.show-matches', queryDialogSk)!;
// Shows "Show Matches" by default.
expect(showMatchesBtn.innerText).to.equal('Show Matches');
// Button label can be changed.
queryDialogSk.submitButtonLabel = 'Submit';
expect(showMatchesBtn.innerText).to.equal('Submit');
});
// Clicks the given key in the query-sk component.
const clickQuerySkKey =
(key: string) =>
$<HTMLDivElement>('query-sk select-sk div', queryDialogSk)
.find(div => div.textContent === key)!
.click();
// Clicks the given value in the query-sk component.
const clickQuerySkValue =
(value: string) =>
$$<HTMLDivElement>(`query-sk multi-select-sk div[value="${value}"]`, queryDialogSk)!.click();
// Clicks the "Show Matches" button. This closes the dialog.
const clickShowMatchesBtn =
() => $$<HTMLButtonElement>('button.show-matches', queryDialogSk)!.click();
// Clicks the "Cancel" button. This closes the dialog.
const clickCancelBtn =
() => $$<HTMLButtonElement>('button.cancel', queryDialogSk)!.click();
// Returns the ParamSet displayed by the query-sk component.
const querySkContents = (onlySelected=false): ParamSet => {
const paramSet: ParamSet = {};
// We'll restore the original selected key after we're done.
const originalSelectedKey =
$$<HTMLDivElement>('query-sk select-sk div[selected]', queryDialogSk);
// Iterate over all keys.
$<HTMLDivElement>('query-sk select-sk div', queryDialogSk).forEach(keyDiv => {
const key = keyDiv.innerText; // Extract key.
keyDiv.click(); // Select the current key.
// Iterate over all values for the current key.
$<HTMLDivElement>('query-sk multi-select-sk div', queryDialogSk).forEach(valueDiv => {
const value = valueDiv.getAttribute('value')!;
const isSelected = valueDiv.hasAttribute('selected');
if (onlySelected && !isSelected) {
return;
}
// Insert current key/value pair into the ParamSet.
if (paramSet[key] === undefined) {
paramSet[key] = [];
}
paramSet[key].push(value);
})
});
// Restore original selected key, if any.
originalSelectedKey?.click();
return paramSet;
}
// Returns the query-sk component's selection.
const querySkSelection = () => querySkContents(/* onlySelected= */ true);
// Returns the ParamSet displayed by the paramset-sk component.
const paramSetSkContents = (): ParamSet => {
const paramSet: ParamSet = {};
$('paramset-sk tr', queryDialogSk).forEach((tr, i) => {
if (i === 0) return; // Skip the first row, which usually displays titles (empty in our case).
const key = $$('th', tr)!.textContent!;
const values = $('div', tr).map(div => div.textContent!);
paramSet[key] = values;
})
return paramSet;
}
const isEmptySelectionPlaceholderTextVisible =
() => $$('p.empty-selection', queryDialogSk) !== null;
const isParamSetSkVisible =
() => $$('param-set-sk', queryDialogSk) !== null;
});