blob: d1802d289acab054fb1db0e5110c19119e3acc37 [file] [log] [blame]
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {createChange} from '../../test/test-data-generators';
import {ChangeInfo, NumericChangeId} from '../../api/rest-api';
import {BulkActionsModel, LoadingState} from './bulk-actions-model';
import {getAppContext} from '../../services/app-context';
import '../../test/common-test-setup-karma';
import {stubRestApi, waitUntilObserved} from '../../test/test-utils';
import {mockPromise, MockPromise} from '../../test/test-utils';
import {
listChangesOptionsToHex,
ListChangesOption,
} from '../../utils/change-util';
const EXPECTED_QUERY_OPTIONS = listChangesOptionsToHex(
ListChangesOption.CHANGE_ACTIONS,
ListChangesOption.CURRENT_ACTIONS,
ListChangesOption.CURRENT_REVISION,
ListChangesOption.DETAILED_LABELS
);
suite('bulk actions model test', () => {
let bulkActionsModel: BulkActionsModel;
setup(() => {
bulkActionsModel = new BulkActionsModel(getAppContext().restApiService);
});
test('add changes before sync', () => {
const c1 = createChange();
c1._number = 1 as NumericChangeId;
const c2 = createChange();
c2._number = 2 as NumericChangeId;
assert.isEmpty(bulkActionsModel.getState().selectedChangeNums);
assert.throws(() => bulkActionsModel.addSelectedChangeNum(c1._number));
assert.isEmpty(bulkActionsModel.getState().selectedChangeNums);
bulkActionsModel.sync([c1, c2]);
bulkActionsModel.addSelectedChangeNum(c2._number);
assert.sameMembers(bulkActionsModel.getState().selectedChangeNums, [
c2._number,
]);
bulkActionsModel.removeSelectedChangeNum(c2._number);
assert.isEmpty(bulkActionsModel.getState().selectedChangeNums);
});
test('add and remove selected changes', () => {
const c1 = createChange();
c1._number = 1 as NumericChangeId;
const c2 = createChange();
c2._number = 2 as NumericChangeId;
bulkActionsModel.sync([c1, c2]);
assert.isEmpty(bulkActionsModel.getState().selectedChangeNums);
bulkActionsModel.addSelectedChangeNum(c1._number);
assert.sameMembers(bulkActionsModel.getState().selectedChangeNums, [
c1._number,
]);
bulkActionsModel.addSelectedChangeNum(c2._number);
assert.sameMembers(bulkActionsModel.getState().selectedChangeNums, [
c1._number,
c2._number,
]);
bulkActionsModel.removeSelectedChangeNum(c1._number);
assert.sameMembers(bulkActionsModel.getState().selectedChangeNums, [
c2._number,
]);
bulkActionsModel.removeSelectedChangeNum(c2._number);
assert.isEmpty(bulkActionsModel.getState().selectedChangeNums);
});
test('stale changes are removed from the model', async () => {
const c1 = createChange();
c1._number = 1 as NumericChangeId;
const c2 = createChange();
c2._number = 2 as NumericChangeId;
bulkActionsModel.sync([c1, c2]);
bulkActionsModel.addSelectedChangeNum(c1._number);
bulkActionsModel.addSelectedChangeNum(c2._number);
let selectedChangeNums = await waitUntilObserved(
bulkActionsModel!.selectedChangeNums$,
s => s.length === 2
);
assert.sameMembers(selectedChangeNums, [c1._number, c2._number]);
bulkActionsModel.sync([c1]);
selectedChangeNums = await waitUntilObserved(
bulkActionsModel!.selectedChangeNums$,
s => s.length === 1
);
assert.sameMembers(selectedChangeNums, [c1._number]);
});
test('sync fetches new changes', async () => {
const c1 = createChange();
c1._number = 1 as NumericChangeId;
const c2 = createChange();
c2._number = 2 as NumericChangeId;
assert.equal(
bulkActionsModel.getState().loadingState,
LoadingState.NOT_SYNCED
);
const responsePromise: MockPromise<ChangeInfo[]> = mockPromise();
const getChangesStub = stubRestApi('getChanges').callsFake(
(changesPerPage, query, offset, options) => {
assert.isUndefined(changesPerPage);
assert.strictEqual(query, 'change:1 OR change:2');
assert.isUndefined(offset);
assert.strictEqual(options, EXPECTED_QUERY_OPTIONS);
return responsePromise;
}
);
bulkActionsModel.sync([c1, c2]);
assert.isTrue(getChangesStub.calledOnce);
await waitUntilObserved(
bulkActionsModel.loadingState$,
s => s === LoadingState.LOADING
);
responsePromise.resolve([
{...createChange(), _number: 1, subject: 'Subject 1'},
{...createChange(), _number: 2, subject: 'Subject 2'},
] as ChangeInfo[]);
await waitUntilObserved(
bulkActionsModel.loadingState$,
s => s === LoadingState.LOADED
);
assert.strictEqual(
bulkActionsModel.allChanges.get(1 as NumericChangeId)?.subject,
'Subject 1'
);
assert.strictEqual(
bulkActionsModel.allChanges.get(2 as NumericChangeId)?.subject,
'Subject 2'
);
});
test('sync ignores outdated fetch responses', async () => {
const c1 = createChange();
c1._number = 1 as NumericChangeId;
const c2 = createChange();
c2._number = 2 as NumericChangeId;
const responsePromise1 = mockPromise<ChangeInfo[]>();
let promise = responsePromise1;
const getChangesStub = stubRestApi('getChanges').callsFake(
(changesPerPage, query, offset, options) => {
assert.isUndefined(changesPerPage);
assert.strictEqual(query, 'change:1 OR change:2');
assert.isUndefined(offset);
assert.strictEqual(options, EXPECTED_QUERY_OPTIONS);
return promise;
}
);
bulkActionsModel.sync([c1, c2]);
assert.strictEqual(getChangesStub.callCount, 1);
await waitUntilObserved(
bulkActionsModel.loadingState$,
s => s === LoadingState.LOADING
);
const responsePromise2 = mockPromise<ChangeInfo[]>();
promise = responsePromise2;
bulkActionsModel.sync([c1, c2]);
assert.strictEqual(getChangesStub.callCount, 2);
responsePromise2.resolve([
{...createChange(), _number: 1, subject: 'Subject 1'},
{...createChange(), _number: 2, subject: 'Subject 2'},
] as ChangeInfo[]);
await waitUntilObserved(
bulkActionsModel.loadingState$,
s => s === LoadingState.LOADED
);
assert.strictEqual(
bulkActionsModel.allChanges.get(1 as NumericChangeId)?.subject,
'Subject 1'
);
assert.strictEqual(
bulkActionsModel.allChanges.get(2 as NumericChangeId)?.subject,
'Subject 2'
);
// Resolve the old promise.
responsePromise1.resolve([
{...createChange(), _number: 1, subject: 'Subject 1-old'},
{...createChange(), _number: 2, subject: 'Subject 2-old'},
] as ChangeInfo[]);
await flush();
// No change should happen.
assert.strictEqual(
bulkActionsModel.allChanges.get(1 as NumericChangeId)?.subject,
'Subject 1'
);
assert.strictEqual(
bulkActionsModel.allChanges.get(2 as NumericChangeId)?.subject,
'Subject 2'
);
});
});