blob: acf0462fdbc97a39f1849ac6d1f6f8bf103ed85d [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} from '../../test/test-utils';
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('clears selected change numbers', 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
);
let totalChangeCount = await waitUntilObserved(
bulkActionsModel.totalChangeCount$,
totalChangeCount => totalChangeCount === 2
);
assert.sameMembers(selectedChangeNums, [c1._number, c2._number]);
assert.equal(totalChangeCount, 2);
bulkActionsModel.clearSelectedChangeNums();
selectedChangeNums = await waitUntilObserved(
bulkActionsModel!.selectedChangeNums$,
s => s.length === 0
);
totalChangeCount = await waitUntilObserved(
bulkActionsModel.totalChangeCount$,
totalChangeCount => totalChangeCount === 2
);
assert.isEmpty(selectedChangeNums);
assert.equal(totalChangeCount, 2);
});
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
);
let totalChangeCount = await waitUntilObserved(
bulkActionsModel.totalChangeCount$,
totalChangeCount => totalChangeCount === 2
);
assert.sameMembers(selectedChangeNums, [c1._number, c2._number]);
assert.equal(totalChangeCount, 2);
bulkActionsModel.sync([c1]);
selectedChangeNums = await waitUntilObserved(
bulkActionsModel!.selectedChangeNums$,
s => s.length === 1
);
totalChangeCount = await waitUntilObserved(
bulkActionsModel.totalChangeCount$,
totalChangeCount => totalChangeCount === 1
);
assert.sameMembers(selectedChangeNums, [c1._number]);
assert.equal(totalChangeCount, 1);
});
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
);
bulkActionsModel.sync([c1, c2]);
await waitUntilObserved(
bulkActionsModel.loadingState$,
s => s === LoadingState.LOADING
);
await waitUntilObserved(
bulkActionsModel.loadingState$,
s => s === LoadingState.LOADED
);
const model = bulkActionsModel.getState();
assert.strictEqual(
model.allChanges.get(1 as NumericChangeId)?.subject,
'Subject 1'
);
assert.strictEqual(
model.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(
'getDetailedChangesWithActions'
).callsFake(() => 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
);
const model = bulkActionsModel.getState();
assert.strictEqual(
model.allChanges.get(1 as NumericChangeId)?.subject,
'Subject 1'
);
assert.strictEqual(
model.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();
const model2 = bulkActionsModel.getState();
// No change should happen.
assert.strictEqual(
model2.allChanges.get(1 as NumericChangeId)?.subject,
'Subject 1'
);
assert.strictEqual(
model2.allChanges.get(2 as NumericChangeId)?.subject,
'Subject 2'
);
});
});