blob: 0d3df42f60a671ac7c669916b25fd2b32e178afe [file] [log] [blame]
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../../test/common-test-setup';
import {
createAccountWithEmail,
createChangeViewState,
createDraft,
} from '../../test/test-data-generators';
import {
AccountInfo,
CommentInfo,
EmailAddress,
NumericChangeId,
Timestamp,
UrlEncodedCommentId,
} from '../../types/common';
import {CommentsModel, deleteDraft} from './comments-model';
import {Subscription} from 'rxjs';
import {
createComment,
createParsedChange,
} from '../../test/test-data-generators';
import {stubRestApi, waitUntil, waitUntilCalled} from '../../test/test-utils';
import {getAppContext} from '../../services/app-context';
import {changeModelToken} from '../change/change-model';
import {assert} from '@open-wc/testing';
import {testResolver} from '../../test/common-test-setup';
import {accountsModelToken} from '../accounts-model/accounts-model';
import {ChangeComments} from '../../elements/diff/gr-comment-api/gr-comment-api';
import {changeViewModelToken} from '../views/change';
import {navigationToken} from '../../elements/core/gr-navigation/gr-navigation';
suite('comments model tests', () => {
test('updateStateDeleteDraft', () => {
const draft = createDraft();
draft.id = '1' as UrlEncodedCommentId;
const state = {
comments: {},
robotComments: {},
drafts: {
[draft.path!]: [draft],
},
portedComments: {},
portedDrafts: {},
discardedDrafts: [],
};
const output = deleteDraft(state, draft);
assert.deepEqual(output, {
comments: {},
robotComments: {},
drafts: {
'abc.txt': [],
},
portedComments: {},
portedDrafts: {},
discardedDrafts: [{...draft}],
});
});
});
suite('change service tests', () => {
let subscriptions: Subscription[] = [];
teardown(() => {
for (const s of subscriptions) {
s.unsubscribe();
}
subscriptions = [];
});
test('loads comments', async () => {
const model = new CommentsModel(
testResolver(changeViewModelToken),
testResolver(changeModelToken),
testResolver(accountsModelToken),
getAppContext().restApiService,
getAppContext().reportingService,
testResolver(navigationToken)
);
const diffCommentsSpy = stubRestApi('getDiffComments').returns(
Promise.resolve({'foo.c': [createComment()]})
);
const diffRobotCommentsSpy = stubRestApi('getDiffRobotComments').returns(
Promise.resolve({})
);
const diffDraftsSpy = stubRestApi('getDiffDrafts').returns(
Promise.resolve({})
);
const portedCommentsSpy = stubRestApi('getPortedComments').returns(
Promise.resolve({'foo.c': [createComment()]})
);
const portedDraftsSpy = stubRestApi('getPortedDrafts').returns(
Promise.resolve({})
);
let comments: {[path: string]: CommentInfo[]} = {};
subscriptions.push(model.comments$.subscribe(c => (comments = c ?? {})));
let portedComments: {[path: string]: CommentInfo[]} = {};
subscriptions.push(
model.portedComments$.subscribe(c => (portedComments = c ?? {}))
);
testResolver(changeViewModelToken).setState(createChangeViewState());
testResolver(changeModelToken).updateStateChange(createParsedChange());
await waitUntilCalled(diffCommentsSpy, 'diffCommentsSpy');
await waitUntilCalled(diffRobotCommentsSpy, 'diffRobotCommentsSpy');
await waitUntilCalled(diffDraftsSpy, 'diffDraftsSpy');
await waitUntilCalled(portedCommentsSpy, 'portedCommentsSpy');
await waitUntilCalled(portedDraftsSpy, 'portedDraftsSpy');
await waitUntil(
() => Object.keys(comments).length > 0,
'comment in model not set'
);
await waitUntil(
() => Object.keys(portedComments).length > 0,
'ported comment in model not set'
);
assert.equal(comments['foo.c'].length, 1);
assert.equal(comments['foo.c'][0].id, '12345');
assert.equal(portedComments['foo.c'].length, 1);
assert.equal(portedComments['foo.c'][0].id, '12345');
});
test('duplicate mentions are filtered out', async () => {
const account = {
...createAccountWithEmail('abcd@def.com' as EmailAddress),
registered_on: '2015-03-12 18:32:08.000000000' as Timestamp,
};
stubRestApi('getAccountDetails').returns(Promise.resolve(account));
const model = new CommentsModel(
testResolver(changeViewModelToken),
testResolver(changeModelToken),
testResolver(accountsModelToken),
getAppContext().restApiService,
getAppContext().reportingService,
testResolver(navigationToken)
);
let mentionedUsers: AccountInfo[] = [];
const draft = {...createDraft(), message: 'hey @abc@def.com'};
model.mentionedUsersInDrafts$.subscribe(x => (mentionedUsers = x));
model.setState({
drafts: {
'abc.txt': [draft, draft],
},
discardedDrafts: [],
});
await waitUntil(() => mentionedUsers.length > 0);
assert.deepEqual(mentionedUsers, [account]);
});
test('empty mentions are emitted', async () => {
const account = {
...createAccountWithEmail('abcd@def.com' as EmailAddress),
registered_on: '2015-03-12 18:32:08.000000000' as Timestamp,
};
stubRestApi('getAccountDetails').returns(Promise.resolve(account));
const model = new CommentsModel(
testResolver(changeViewModelToken),
testResolver(changeModelToken),
testResolver(accountsModelToken),
getAppContext().restApiService,
getAppContext().reportingService,
testResolver(navigationToken)
);
let mentionedUsers: AccountInfo[] = [];
const draft = {...createDraft(), message: 'hey @abc@def.com'};
model.mentionedUsersInDrafts$.subscribe(x => (mentionedUsers = x));
model.setState({
drafts: {
'abc.txt': [draft],
},
discardedDrafts: [],
});
await waitUntil(() => mentionedUsers.length > 0);
assert.deepEqual(mentionedUsers, [account]);
model.setState({
drafts: {
'abc.txt': [],
},
discardedDrafts: [],
});
await waitUntil(() => mentionedUsers.length === 0);
});
test('delete comment change is emitted', async () => {
const comment = createComment();
stubRestApi('deleteComment').returns(
Promise.resolve({
...comment,
message: 'Comment is deleted',
})
);
const model = new CommentsModel(
testResolver(changeViewModelToken),
testResolver(changeModelToken),
testResolver(accountsModelToken),
getAppContext().restApiService,
getAppContext().reportingService,
testResolver(navigationToken)
);
let changeComments: ChangeComments | undefined = undefined;
model.changeComments$.subscribe(x => (changeComments = x));
model.setState({
comments: {[comment.path!]: [comment]},
discardedDrafts: [],
});
model.deleteComment(123 as NumericChangeId, comment, 'Comment is deleted');
await waitUntil(
() =>
changeComments?.getAllCommentsForPath(comment.path!)[0].message ===
'Comment is deleted'
);
});
});