blob: cb3b3113f366515734abac11f62fdb87ff8804c1 [file] [log] [blame]
import './index';
import { $, $$ } from 'common-sk/modules/dom';
import { setUpElementUnderTest, eventPromise } from '../../../infra-sk/modules/test_util';
import { ParamSet } from 'common-sk/modules/query';
import { SearchControlsSk, SearchCriteria } from './search-controls-sk';
import { CheckOrRadio } from 'elements-sk/checkbox-sk/checkbox-sk';
const expect = chai.expect;
describe('search-controls-sk', () => {
const corpora = ['canvaskit', 'colorImage', 'gm', 'image', 'pathkit', 'skp', 'svg'];
const paramSet: ParamSet = {
'car make': ['chevrolet', 'dodge', 'ford', 'lincoln motor company'],
'color': ['blue', 'green', 'red'],
'used': ['yes', 'no'],
'year': ['2020', '2019', '2018', '2017', '2016', '2015']
};
// Takes a partial SearchCriteria and returns a full SearchCriteria by filling any missing fields
// with either zero values or sensible defaults.
const makeSearchCriteria = (partial: Partial<SearchCriteria> = {}) => {
const defaults: SearchCriteria = {
corpus: 'gm',
leftHandTraceFilter: {},
rightHandTraceFilter: {},
includePositiveDigests: false,
includeNegativeDigests: false,
includeUntriagedDigests: false,
includeDigestsNotAtHead: false,
includeIgnoredDigests: false,
minRGBADelta: 0,
maxRGBADelta: 0,
mustHaveReferenceImage: false,
sortOrder: 'ascending'
};
return {...defaults, ...partial};
}
const newInstance = setUpElementUnderTest<SearchControlsSk>('search-controls-sk');
let searchControlsSk: SearchControlsSk;
beforeEach(() => {
searchControlsSk = newInstance();
searchControlsSk.corpora = corpora;
searchControlsSk.paramSet = paramSet;
searchControlsSk.searchCriteria = makeSearchCriteria();
});
it('shows the initial value', () => {
expect(getSearchCriteriaFromUI()).to.deep.equal(makeSearchCriteria());
});
describe('corpus', () => {
const searchCriteria = makeSearchCriteria({corpus: 'image'});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
expect(getCorpus()).to.equal('image');
});
it('can change via the UI', async () => {
const event = changeEventPromise();
clickCorpus('image');
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('include positive digests', () => {
const searchCriteria = makeSearchCriteria({includePositiveDigests: true});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
expect(getIncludePositiveDigestsCheckBox().checked).to.be.true;
});
it('can change via the UI', async () => {
const event = changeEventPromise();
getIncludePositiveDigestsCheckBox().click();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('include negative digests', () => {
const searchCriteria = makeSearchCriteria({includeNegativeDigests: true});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
expect(getIncludeNegativeDigestsCheckBox().checked).to.be.true;
});
it('can change via the UI', async () => {
const event = changeEventPromise();
getIncludeNegativeDigestsCheckBox().click();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('include untriaged digests', () => {
const searchCriteria = makeSearchCriteria({includeUntriagedDigests: true});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
expect(getIncludeUntriagedDigestsCheckBox().checked).to.be.true;
});
it('can change via the UI', async () => {
const event = changeEventPromise();
getIncludeUntriagedDigestsCheckBox().click();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('include digests not at HEAD', () => {
const searchCriteria = makeSearchCriteria({includeDigestsNotAtHead: true});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
expect(getIncludeDigestsNotAtHeadCheckBox().checked).to.be.true;
});
it('can change via the UI', async () => {
const event = changeEventPromise();
getIncludeDigestsNotAtHeadCheckBox().click();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('include ignored digests', () => {
const searchCriteria = makeSearchCriteria({includeIgnoredDigests: true});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
expect(getIncludeIgnoredDigestsCheckBox().checked).to.be.true;
});
it('can change via the UI', async () => {
const event = changeEventPromise();
getIncludeIgnoredDigestsCheckBox().click();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('left-hand trace filter', () => {
it('can change programmatically', () => {
searchControlsSk.searchCriteria =
makeSearchCriteria({leftHandTraceFilter: {'car make': ['ford']}});
expect(getLeftHandTraceFilterValue()).to.deep.equal({'car make': ['ford']});
});
it('can change via the UI', async () => {
const event = changeEventPromise();
const traceFilter = changeLeftHandTraceFilter();
expect((await event).detail)
.to.deep.equal(makeSearchCriteria({leftHandTraceFilter: traceFilter}));
expect(searchControlsSk.searchCriteria)
.to.deep.equal(makeSearchCriteria({leftHandTraceFilter: traceFilter}));
});
});
describe('more filters', () => {
describe('right-hand trace filter', () => {
it('can change programmatically', () => {
searchControlsSk.searchCriteria =
makeSearchCriteria({rightHandTraceFilter: {'car make': ['ford']}});
clickMoreFiltersBtn();
expect(getRightHandTraceFilterValue()).to.deep.equal({'car make': ['ford']});
});
it('can change via the UI', async () => {
const event = changeEventPromise();
clickMoreFiltersBtn();
const traceFilter = changeRightHandTraceFilter();
clickFilterDialogSubmitBtn();
expect((await event).detail)
.to.deep.equal(makeSearchCriteria({rightHandTraceFilter: traceFilter}));
expect(searchControlsSk.searchCriteria)
.to.deep.equal(makeSearchCriteria({rightHandTraceFilter: traceFilter}));
});
});
describe('min RGBA delta', () => {
// Arbitrary number in the middle of the allowed range (0 to 255).
const searchCriteria = makeSearchCriteria({minRGBADelta: 100});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
clickMoreFiltersBtn();
expect(getMinRGBADeltaInput().value).to.equal('100');
});
it('can change via the UI', async () => {
const event = changeEventPromise();
clickMoreFiltersBtn();
getMinRGBADeltaInput().value = '100';
getMinRGBADeltaInput().dispatchEvent(new CustomEvent('input')); // Simulate UI interaction.
clickFilterDialogSubmitBtn();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('max RGBA delta', () => {
// Arbitrary number in the middle of the allowed range (0 to 255).
const searchCriteria = makeSearchCriteria({maxRGBADelta: 100});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
clickMoreFiltersBtn();
expect(getMaxRGBADeltaInput().value).to.equal('100');
});
it('can change via the UI', async () => {
const event = changeEventPromise();
clickMoreFiltersBtn();
getMaxRGBADeltaInput().value = '100';
getMaxRGBADeltaInput().dispatchEvent(new CustomEvent('input')); // Simulate UI interaction.
clickFilterDialogSubmitBtn();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('sort order', () => {
const searchCriteria = makeSearchCriteria({sortOrder: 'descending'});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
clickMoreFiltersBtn();
expect(getSortOrderSelect().value).to.equal('descending');
});
it('can change via the UI', async () => {
const event = changeEventPromise();
clickMoreFiltersBtn();
getSortOrderSelect().value = 'descending';
getSortOrderSelect().dispatchEvent(new CustomEvent('change')); // Simulate UI interaction.
clickFilterDialogSubmitBtn();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
describe('must have reference image', () => {
const searchCriteria = makeSearchCriteria({mustHaveReferenceImage: true});
it('can change programmatically', () => {
searchControlsSk.searchCriteria = searchCriteria;
clickMoreFiltersBtn();
expect(getMustHaveReferenceImageCheckBox().checked).to.be.true;
});
it('can change via the UI', async () => {
const event = changeEventPromise();
clickMoreFiltersBtn();
getMustHaveReferenceImageCheckBox().click();
clickFilterDialogSubmitBtn();
expect((await event).detail).to.deep.equal(searchCriteria);
expect(searchControlsSk.searchCriteria).to.deep.equal(searchCriteria);
});
});
});
const changeEventPromise =
() => eventPromise<CustomEvent<SearchCriteria>>('search-controls-sk-change');
// Returns the SearchCriteria displayed by the search-controls-sk element by inspecting the DOM.
const getSearchCriteriaFromUI = (): SearchCriteria => {
const searchCriteria: Partial<SearchCriteria> = {}
searchCriteria.corpus = getCorpus();
searchCriteria.leftHandTraceFilter = getLeftHandTraceFilterValue();;
searchCriteria.includePositiveDigests = getIncludePositiveDigestsCheckBox().checked;
searchCriteria.includeNegativeDigests = getIncludeNegativeDigestsCheckBox().checked;
searchCriteria.includeUntriagedDigests = getIncludeUntriagedDigestsCheckBox().checked;
searchCriteria.includeDigestsNotAtHead = getIncludeDigestsNotAtHeadCheckBox().checked;
searchCriteria.includeIgnoredDigests = getIncludeIgnoredDigestsCheckBox().checked;
// More filters dialog.
clickMoreFiltersBtn();
searchCriteria.rightHandTraceFilter = getTraceFilterValue('filter-dialog-sk trace-filter-sk');
searchCriteria.minRGBADelta = parseInt(getMinRGBADeltaInput().value);
searchCriteria.maxRGBADelta = parseInt(getMaxRGBADeltaInput().value);
searchCriteria.mustHaveReferenceImage = getMustHaveReferenceImageCheckBox().checked;
searchCriteria.sortOrder = getSortOrderSelect().value as 'ascending' | 'descending';
clickFilterDialogCancelBtn();
return searchCriteria as SearchCriteria;
};
// Corpus.
const getCorpus =
() => $$<HTMLLIElement>('corpus-selector-sk li.selected', searchControlsSk)!.innerText;
const clickCorpus =
(corpus: string) =>
$<HTMLLIElement>('corpus-selector-sk li', searchControlsSk)
.find(li => li.innerText === corpus)!
.click();
// Checkboxes.
const getIncludePositiveDigestsCheckBox =
() => $$<CheckOrRadio>('.include-positive-digests', searchControlsSk)!;
const getIncludeNegativeDigestsCheckBox =
() => $$<CheckOrRadio>('.include-negative-digests', searchControlsSk)!;
const getIncludeUntriagedDigestsCheckBox =
() => $$<CheckOrRadio>('.include-untriaged-digests', searchControlsSk)!;
const getIncludeDigestsNotAtHeadCheckBox =
() => $$<CheckOrRadio>('.include-digests-not-at-head', searchControlsSk)!;
const getIncludeIgnoredDigestsCheckBox =
() => $$<CheckOrRadio>('.include-ignored-digests', searchControlsSk)!;
// Trace filters.
const getLeftHandTraceFilterValue = () => getTraceFilterValue('.traces trace-filter-sk');
const getRightHandTraceFilterValue =
() => getTraceFilterValue('filter-dialog-sk trace-filter-sk');
const getTraceFilterValue = (selector: string): ParamSet => {
const paramSet: ParamSet = {};
$(`${selector} paramset-sk tr`, searchControlsSk).forEach((tr, i) => {
if (i === 0) return; // Skip the first row, which is empty as there are no titles.
const key = $$('th', tr)!.textContent!;
const values = $('div', tr).map(div => div.textContent!);
paramSet[key] = values;
})
return paramSet;
};
const changeLeftHandTraceFilter = () => {
const selector = '.traces trace-filter-sk query-dialog-sk';
$$<HTMLButtonElement>('.traces .edit-query')!.click();
const newFilter = changeQueryDialogSelection(selector);
clickQueryDialogSubmitBtn(selector);
return newFilter;
};
const changeRightHandTraceFilter = () => {
const selector = 'filter-dialog-sk query-dialog-sk';
$$<HTMLButtonElement>('filter-dialog-sk .edit-query')!.click();
const newFilter = changeQueryDialogSelection(selector);
clickQueryDialogSubmitBtn(selector);
return newFilter;
};
const changeQueryDialogSelection = (queryDialogSelector: string): ParamSet => {
const queryDialogSk = $$(queryDialogSelector, searchControlsSk)!;
$$<HTMLButtonElement>('.clear_selections', queryDialogSk)!.click();
$$<HTMLDivElement>('select-sk div:nth-child(2)', queryDialogSk)!.click(); // Color.
$$<HTMLDivElement>('multi-select-sk div:nth-child(2)', queryDialogSk)!.click(); // Green.
$$<HTMLDivElement>('select-sk div:nth-child(3)', queryDialogSk)!.click(); // Used.
$$<HTMLDivElement>('multi-select-sk div:nth-child(1)', queryDialogSk)!.click(); // Yes.
$$<HTMLDivElement>('multi-select-sk div:nth-child(2)', queryDialogSk)!.click(); // No.
return {'color': ['green'], 'used': ['yes', 'no']};
};
const clickQueryDialogSubmitBtn =
(queryDialogSelector: string) =>
$$<HTMLButtonElement>(`${queryDialogSelector} .show-matches`, searchControlsSk)!.click();
// More filters.
const clickMoreFiltersBtn =
() => $$<HTMLButtonElement>('.more-filters', searchControlsSk)!.click();
const clickFilterDialogSubmitBtn =
() =>
$$<HTMLButtonElement>(
'filter-dialog-sk .filter-dialog > .buttons .filter', searchControlsSk)!.click();
const clickFilterDialogCancelBtn =
() =>
$$<HTMLButtonElement>(
'filter-dialog-sk .filter-dialog > .buttons .cancel', searchControlsSk)!.click();
const getMinRGBADeltaInput =
() => $$<HTMLInputElement>('filter-dialog-sk #min-rgba-delta', searchControlsSk)!;
const getMaxRGBADeltaInput =
() => $$<HTMLInputElement>('filter-dialog-sk #max-rgba-delta', searchControlsSk)!;
const getSortOrderSelect =
() => $$<HTMLSelectElement>('filter-dialog-sk #sort-order', searchControlsSk)!;
const getMustHaveReferenceImageCheckBox =
() => $$<CheckOrRadio>('filter-dialog-sk #must-have-reference-image')!;
});