diffSide property determines on which side of the diff, the thread will be rendered, left or right. The property naturally associates with threads and not comments, so move the determination logic of diffSide to thread-level instead of comment-level. Change-Id: Ifd33918fe24cbc5bb5b2daf25b161cd53cb8b75f
		
			
				
	
	
		
			1018 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			1018 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
/**
 | 
						||
 * @license
 | 
						||
 * Copyright (C) 2015 The Android Open Source Project
 | 
						||
 *
 | 
						||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						||
 * you may not use this file except in compliance with the License.
 | 
						||
 * You may obtain a copy of the License at
 | 
						||
 *
 | 
						||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
						||
 *
 | 
						||
 * Unless required by applicable law or agreed to in writing, software
 | 
						||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						||
 * See the License for the specific language governing permissions and
 | 
						||
 * limitations under the License.
 | 
						||
 */
 | 
						||
 | 
						||
import '../../../test/common-test-setup-karma.js';
 | 
						||
import './gr-comment-thread.js';
 | 
						||
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
 | 
						||
import {SpecialFilePath, Side} from '../../../constants/constants.js';
 | 
						||
import {
 | 
						||
  sortComments,
 | 
						||
  UIComment,
 | 
						||
  UIRobot,
 | 
						||
  isDraft,
 | 
						||
  UIDraft,
 | 
						||
} from '../../../utils/comment-util.js';
 | 
						||
import {GrCommentThread} from './gr-comment-thread.js';
 | 
						||
import {
 | 
						||
  PatchSetNum,
 | 
						||
  NumericChangeId,
 | 
						||
  UrlEncodedCommentId,
 | 
						||
  Timestamp,
 | 
						||
  RobotId,
 | 
						||
  RobotRunId,
 | 
						||
  RepoName,
 | 
						||
  ConfigInfo,
 | 
						||
  EmailAddress,
 | 
						||
} from '../../../types/common.js';
 | 
						||
import {GrComment} from '../gr-comment/gr-comment.js';
 | 
						||
import {LineNumber} from '../../diff/gr-diff/gr-diff-line.js';
 | 
						||
import {
 | 
						||
  tap,
 | 
						||
  pressAndReleaseKeyOn,
 | 
						||
} from '@polymer/iron-test-helpers/mock-interactions';
 | 
						||
 | 
						||
const basicFixture = fixtureFromElement('gr-comment-thread');
 | 
						||
 | 
						||
const withCommentFixture = fixtureFromElement('gr-comment-thread');
 | 
						||
 | 
						||
suite('gr-comment-thread tests', () => {
 | 
						||
  suite('basic test', () => {
 | 
						||
    let element: GrCommentThread;
 | 
						||
 | 
						||
    setup(() => {
 | 
						||
      stub('gr-rest-api-interface', {
 | 
						||
        getLoggedIn() {
 | 
						||
          return Promise.resolve(false);
 | 
						||
        },
 | 
						||
      });
 | 
						||
 | 
						||
      element = basicFixture.instantiate();
 | 
						||
      element.patchNum = 3 as PatchSetNum;
 | 
						||
      element.changeNum = 1 as NumericChangeId;
 | 
						||
      flush();
 | 
						||
    });
 | 
						||
 | 
						||
    test('comments are sorted correctly', () => {
 | 
						||
      const comments: UIComment[] = [
 | 
						||
        {
 | 
						||
          message: 'i like you, too',
 | 
						||
          in_reply_to: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          __date: new Date('2015-12-25'),
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          message: 'i like you, jack',
 | 
						||
          updated: '2015-12-24 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          message: 'i’m running away',
 | 
						||
          updated: '2015-10-31 09:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_defiance' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          message: 'i will poison you so i can get away',
 | 
						||
          updated: '2015-10-31 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'dr_finklesteins_response' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          message: 'no i will pull a thread and your arm will fall off',
 | 
						||
          updated: '2015-10-31 11:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_mission' as UrlEncodedCommentId,
 | 
						||
          message: 'i have to find santa',
 | 
						||
          updated: '2015-12-24 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
      ];
 | 
						||
      const results = sortComments(comments);
 | 
						||
      assert.deepEqual(results, [
 | 
						||
        {
 | 
						||
          id: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          message: 'i’m running away',
 | 
						||
          updated: '2015-10-31 09:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'dr_finklesteins_response' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          message: 'no i will pull a thread and your arm will fall off',
 | 
						||
          updated: '2015-10-31 11:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_defiance' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          message: 'i will poison you so i can get away',
 | 
						||
          updated: '2015-10-31 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          message: 'i like you, jack',
 | 
						||
          updated: '2015-12-24 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_mission' as UrlEncodedCommentId,
 | 
						||
          message: 'i have to find santa',
 | 
						||
          updated: '2015-12-24 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          message: 'i like you, too' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          __date: new Date('2015-12-25'),
 | 
						||
        },
 | 
						||
      ]);
 | 
						||
    });
 | 
						||
 | 
						||
    test('addOrEditDraft w/ edit draft', () => {
 | 
						||
      element.comments = [
 | 
						||
        {
 | 
						||
          id: 'jacks_reply' as UrlEncodedCommentId,
 | 
						||
          message: 'i like you, too',
 | 
						||
          in_reply_to: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          updated: '2015-12-25 15:00:20.396000000' as Timestamp,
 | 
						||
          __draft: true,
 | 
						||
        },
 | 
						||
      ];
 | 
						||
      const commentElStub = sinon
 | 
						||
        .stub(element, '_commentElWithDraftID')
 | 
						||
        .callsFake(() => {
 | 
						||
          return new GrComment();
 | 
						||
        });
 | 
						||
      const addDraftStub = sinon.stub(element, 'addDraft');
 | 
						||
 | 
						||
      element.addOrEditDraft(123);
 | 
						||
 | 
						||
      assert.isTrue(commentElStub.called);
 | 
						||
      assert.isFalse(addDraftStub.called);
 | 
						||
    });
 | 
						||
 | 
						||
    test('addOrEditDraft w/o edit draft', () => {
 | 
						||
      element.comments = [];
 | 
						||
      const commentElStub = sinon
 | 
						||
        .stub(element, '_commentElWithDraftID')
 | 
						||
        .callsFake(() => {
 | 
						||
          return new GrComment();
 | 
						||
        });
 | 
						||
      const addDraftStub = sinon.stub(element, 'addDraft');
 | 
						||
 | 
						||
      element.addOrEditDraft(123);
 | 
						||
 | 
						||
      assert.isFalse(commentElStub.called);
 | 
						||
      assert.isTrue(addDraftStub.called);
 | 
						||
    });
 | 
						||
 | 
						||
    test('_shouldDisableAction', () => {
 | 
						||
      let showActions = true;
 | 
						||
      const lastComment: UIComment = {};
 | 
						||
      assert.equal(
 | 
						||
        element._shouldDisableAction(showActions, lastComment),
 | 
						||
        false
 | 
						||
      );
 | 
						||
      showActions = false;
 | 
						||
      assert.equal(
 | 
						||
        element._shouldDisableAction(showActions, lastComment),
 | 
						||
        true
 | 
						||
      );
 | 
						||
      showActions = true;
 | 
						||
      lastComment.__draft = true;
 | 
						||
      assert.equal(
 | 
						||
        element._shouldDisableAction(showActions, lastComment),
 | 
						||
        true
 | 
						||
      );
 | 
						||
      const robotComment: UIRobot = {
 | 
						||
        id: '1234' as UrlEncodedCommentId,
 | 
						||
        updated: '1234' as Timestamp,
 | 
						||
        robot_id: 'robot_id' as RobotId,
 | 
						||
        robot_run_id: 'robot_run_id' as RobotRunId,
 | 
						||
        properties: {},
 | 
						||
        fix_suggestions: [],
 | 
						||
      };
 | 
						||
      assert.equal(
 | 
						||
        element._shouldDisableAction(showActions, robotComment),
 | 
						||
        false
 | 
						||
      );
 | 
						||
    });
 | 
						||
 | 
						||
    test('_hideActions', () => {
 | 
						||
      let showActions = true;
 | 
						||
      const lastComment: UIComment = {};
 | 
						||
      assert.equal(element._hideActions(showActions, lastComment), false);
 | 
						||
      showActions = false;
 | 
						||
      assert.equal(element._hideActions(showActions, lastComment), true);
 | 
						||
      showActions = true;
 | 
						||
      lastComment.__draft = true;
 | 
						||
      assert.equal(element._hideActions(showActions, lastComment), true);
 | 
						||
      const robotComment: UIRobot = {
 | 
						||
        id: '1234' as UrlEncodedCommentId,
 | 
						||
        updated: '1234' as Timestamp,
 | 
						||
        robot_id: 'robot_id' as RobotId,
 | 
						||
        robot_run_id: 'robot_run_id' as RobotRunId,
 | 
						||
        properties: {},
 | 
						||
        fix_suggestions: [],
 | 
						||
      };
 | 
						||
      assert.equal(element._hideActions(showActions, robotComment), true);
 | 
						||
    });
 | 
						||
 | 
						||
    test('setting project name loads the project config', done => {
 | 
						||
      const projectName = 'foo/bar/baz' as RepoName;
 | 
						||
      const getProjectStub = sinon
 | 
						||
        .stub(element.restApiService, 'getProjectConfig')
 | 
						||
        .returns(Promise.resolve({} as ConfigInfo));
 | 
						||
      element.projectName = projectName;
 | 
						||
      flush(() => {
 | 
						||
        assert.isTrue(getProjectStub.calledWithExactly(projectName));
 | 
						||
        done();
 | 
						||
      });
 | 
						||
    });
 | 
						||
 | 
						||
    test('optionally show file path', () => {
 | 
						||
      // Path info doesn't exist when showFilePath is false. Because it's in a
 | 
						||
      // dom-if it is not yet in the dom.
 | 
						||
      assert.isNotOk(element.shadowRoot?.querySelector('.pathInfo'));
 | 
						||
 | 
						||
      const commentStub = sinon.stub(GerritNav, 'getUrlForComment');
 | 
						||
      element.changeNum = 123 as NumericChangeId;
 | 
						||
      element.projectName = 'test project' as RepoName;
 | 
						||
      element.path = 'path/to/file';
 | 
						||
      element.patchNum = 3 as PatchSetNum;
 | 
						||
      element.lineNum = 5;
 | 
						||
      element.comments = [{id: 'comment_id' as UrlEncodedCommentId}];
 | 
						||
      element.showFilePath = true;
 | 
						||
      flush();
 | 
						||
      assert.isOk(element.shadowRoot?.querySelector('.pathInfo'));
 | 
						||
      assert.notEqual(
 | 
						||
        getComputedStyle(element.shadowRoot!.querySelector('.pathInfo')!)
 | 
						||
          .display,
 | 
						||
        'none'
 | 
						||
      );
 | 
						||
      assert.isTrue(
 | 
						||
        commentStub.calledWithExactly(
 | 
						||
          element.changeNum,
 | 
						||
          element.projectName,
 | 
						||
          'comment_id' as UrlEncodedCommentId
 | 
						||
        )
 | 
						||
      );
 | 
						||
    });
 | 
						||
 | 
						||
    test('_computeDisplayPath', () => {
 | 
						||
      let path = 'path/to/file';
 | 
						||
      assert.equal(element._computeDisplayPath(path), 'path/to/file');
 | 
						||
 | 
						||
      element.lineNum = 5;
 | 
						||
      assert.equal(element._computeDisplayPath(path), 'path/to/file');
 | 
						||
 | 
						||
      element.patchNum = 3 as PatchSetNum;
 | 
						||
      path = SpecialFilePath.PATCHSET_LEVEL_COMMENTS;
 | 
						||
      assert.equal(element._computeDisplayPath(path), 'Patchset');
 | 
						||
    });
 | 
						||
 | 
						||
    test('_computeDisplayLine', () => {
 | 
						||
      element.lineNum = 5;
 | 
						||
      assert.equal(element._computeDisplayLine(), '#5');
 | 
						||
 | 
						||
      element.path = SpecialFilePath.COMMIT_MESSAGE;
 | 
						||
      element.lineNum = 5;
 | 
						||
      assert.equal(element._computeDisplayLine(), '#5');
 | 
						||
 | 
						||
      element.lineNum = undefined;
 | 
						||
      element.path = SpecialFilePath.PATCHSET_LEVEL_COMMENTS;
 | 
						||
      assert.equal(element._computeDisplayLine(), '');
 | 
						||
    });
 | 
						||
  });
 | 
						||
});
 | 
						||
 | 
						||
suite('comment action tests with unresolved thread', () => {
 | 
						||
  let element: GrCommentThread;
 | 
						||
 | 
						||
  setup(() => {
 | 
						||
    stub('gr-rest-api-interface', {
 | 
						||
      getLoggedIn() {
 | 
						||
        return Promise.resolve(false);
 | 
						||
      },
 | 
						||
      saveDiffDraft() {
 | 
						||
        return Promise.resolve(({
 | 
						||
          headers: {} as Headers,
 | 
						||
          redirected: false,
 | 
						||
          status: 200,
 | 
						||
          statusText: '',
 | 
						||
          type: '' as ResponseType,
 | 
						||
          url: '',
 | 
						||
          ok: true,
 | 
						||
          text() {
 | 
						||
            return Promise.resolve(
 | 
						||
              ")]}'\n" +
 | 
						||
                JSON.stringify({
 | 
						||
                  id: '7afa4931_de3d65bd',
 | 
						||
                  path: '/path/to/file.txt',
 | 
						||
                  line: 5,
 | 
						||
                  in_reply_to: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
                  updated: '2015-12-21 02:01:10.850000000',
 | 
						||
                  message: 'Done',
 | 
						||
                })
 | 
						||
            );
 | 
						||
          },
 | 
						||
        } as unknown) as Response);
 | 
						||
      },
 | 
						||
      deleteDiffDraft() {
 | 
						||
        return Promise.resolve(({ok: true} as unknown) as Response);
 | 
						||
      },
 | 
						||
    });
 | 
						||
    element = withCommentFixture.instantiate();
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    element.changeNum = 1 as NumericChangeId;
 | 
						||
    element.comments = [
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter',
 | 
						||
          email: ('tenn1sballchaser@aol.com' as EmailAddress) as EmailAddress,
 | 
						||
        },
 | 
						||
        id: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
        line: 5,
 | 
						||
        message: 'is this a crossover episode!?',
 | 
						||
        updated: '2015-12-08 19:48:33.843000000' as Timestamp,
 | 
						||
        path: '/path/to/file.txt',
 | 
						||
        unresolved: true,
 | 
						||
        patch_set: 3 as PatchSetNum,
 | 
						||
      },
 | 
						||
    ];
 | 
						||
    flush();
 | 
						||
  });
 | 
						||
 | 
						||
  test('reply', () => {
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    const reportStub = sinon.stub(element.reporting, 'recordDraftInteraction');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const replyBtn = element.$.replyBtn;
 | 
						||
    tap(replyBtn);
 | 
						||
    flush();
 | 
						||
 | 
						||
    const drafts = element._orderedComments.filter(c => isDraft(c));
 | 
						||
    assert.equal(drafts.length, 1);
 | 
						||
    assert.notOk(drafts[0].message, 'message should be empty');
 | 
						||
    assert.equal(
 | 
						||
      drafts[0].in_reply_to,
 | 
						||
      ('baf0414d_60047215' as UrlEncodedCommentId) as UrlEncodedCommentId
 | 
						||
    );
 | 
						||
    assert.isTrue(reportStub.calledOnce);
 | 
						||
  });
 | 
						||
 | 
						||
  test('quote reply', () => {
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    const reportStub = sinon.stub(element.reporting, 'recordDraftInteraction');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const quoteBtn = element.$.quoteBtn;
 | 
						||
    tap(quoteBtn);
 | 
						||
    flush();
 | 
						||
 | 
						||
    const drafts = element._orderedComments.filter(c => isDraft(c));
 | 
						||
    assert.equal(drafts.length, 1);
 | 
						||
    assert.equal(drafts[0].message, '> is this a crossover episode!?\n\n');
 | 
						||
    assert.equal(
 | 
						||
      drafts[0].in_reply_to,
 | 
						||
      ('baf0414d_60047215' as UrlEncodedCommentId) as UrlEncodedCommentId
 | 
						||
    );
 | 
						||
    assert.isTrue(reportStub.calledOnce);
 | 
						||
  });
 | 
						||
 | 
						||
  test('quote reply multiline', () => {
 | 
						||
    const reportStub = sinon.stub(element.reporting, 'recordDraftInteraction');
 | 
						||
    element.comments = [
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter',
 | 
						||
          email: ('tenn1sballchaser@aol.com' as EmailAddress) as EmailAddress,
 | 
						||
        },
 | 
						||
        id: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
        path: 'test',
 | 
						||
        line: 5,
 | 
						||
        message: 'is this a crossover episode!?\nIt might be!',
 | 
						||
        updated: '2015-12-08 19:48:33.843000000' as Timestamp,
 | 
						||
      },
 | 
						||
    ];
 | 
						||
    flush();
 | 
						||
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const quoteBtn = element.$.quoteBtn;
 | 
						||
    tap(quoteBtn);
 | 
						||
    flush();
 | 
						||
 | 
						||
    const drafts = element._orderedComments.filter(c => isDraft(c));
 | 
						||
    assert.equal(drafts.length, 1);
 | 
						||
    assert.equal(
 | 
						||
      drafts[0].message,
 | 
						||
      '> is this a crossover episode!?\n> It might be!\n\n'
 | 
						||
    );
 | 
						||
    assert.equal(
 | 
						||
      drafts[0].in_reply_to,
 | 
						||
      'baf0414d_60047215' as UrlEncodedCommentId
 | 
						||
    );
 | 
						||
    assert.isTrue(reportStub.calledOnce);
 | 
						||
  });
 | 
						||
 | 
						||
  test('ack', done => {
 | 
						||
    const reportStub = sinon.stub(element.reporting, 'recordDraftInteraction');
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const ackBtn = element.shadowRoot?.querySelector('#ackBtn');
 | 
						||
    assert.isOk(ackBtn);
 | 
						||
    tap(ackBtn!);
 | 
						||
    flush(() => {
 | 
						||
      const drafts = element.comments.filter(c => isDraft(c));
 | 
						||
      assert.equal(drafts.length, 1);
 | 
						||
      assert.equal(drafts[0].message, 'Ack');
 | 
						||
      assert.equal(
 | 
						||
        drafts[0].in_reply_to,
 | 
						||
        'baf0414d_60047215' as UrlEncodedCommentId
 | 
						||
      );
 | 
						||
      assert.equal(drafts[0].unresolved, false);
 | 
						||
      assert.isTrue(reportStub.calledOnce);
 | 
						||
      done();
 | 
						||
    });
 | 
						||
  });
 | 
						||
 | 
						||
  test('done', done => {
 | 
						||
    const reportStub = sinon.stub(element.reporting, 'recordDraftInteraction');
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const doneBtn = element.shadowRoot?.querySelector('#doneBtn');
 | 
						||
    assert.isOk(doneBtn);
 | 
						||
    tap(doneBtn!);
 | 
						||
    flush(() => {
 | 
						||
      const drafts = element.comments.filter(c => isDraft(c));
 | 
						||
      assert.equal(drafts.length, 1);
 | 
						||
      assert.equal(drafts[0].message, 'Done');
 | 
						||
      assert.equal(
 | 
						||
        drafts[0].in_reply_to,
 | 
						||
        'baf0414d_60047215' as UrlEncodedCommentId
 | 
						||
      );
 | 
						||
      assert.isFalse(drafts[0].unresolved);
 | 
						||
      assert.isTrue(reportStub.calledOnce);
 | 
						||
      done();
 | 
						||
    });
 | 
						||
  });
 | 
						||
 | 
						||
  test('save', done => {
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    element.path = '/path/to/file.txt';
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const saveOrDiscardStub = sinon.stub();
 | 
						||
    element.addEventListener('thread-changed', saveOrDiscardStub);
 | 
						||
    element.shadowRoot?.querySelector('gr-comment')?._fireSave();
 | 
						||
 | 
						||
    flush(() => {
 | 
						||
      assert.isTrue(saveOrDiscardStub.called);
 | 
						||
      assert.equal(
 | 
						||
        saveOrDiscardStub.lastCall.args[0].detail.rootId,
 | 
						||
        'baf0414d_60047215'
 | 
						||
      );
 | 
						||
      assert.equal(element.rootId, 'baf0414d_60047215' as UrlEncodedCommentId);
 | 
						||
      assert.equal(
 | 
						||
        saveOrDiscardStub.lastCall.args[0].detail.path,
 | 
						||
        '/path/to/file.txt'
 | 
						||
      );
 | 
						||
      done();
 | 
						||
    });
 | 
						||
  });
 | 
						||
 | 
						||
  test('please fix', done => {
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
    commentEl!.addEventListener('create-fix-comment', () => {
 | 
						||
      const drafts = element._orderedComments.filter(c => isDraft(c));
 | 
						||
      assert.equal(drafts.length, 1);
 | 
						||
      assert.equal(
 | 
						||
        drafts[0].message,
 | 
						||
        '> is this a crossover episode!?\n\nPlease fix.'
 | 
						||
      );
 | 
						||
      assert.equal(
 | 
						||
        drafts[0].in_reply_to,
 | 
						||
        'baf0414d_60047215' as UrlEncodedCommentId
 | 
						||
      );
 | 
						||
      assert.isTrue(drafts[0].unresolved);
 | 
						||
      done();
 | 
						||
    });
 | 
						||
    commentEl!.dispatchEvent(
 | 
						||
      new CustomEvent('create-fix-comment', {
 | 
						||
        detail: {comment: commentEl!.comment},
 | 
						||
        composed: true,
 | 
						||
        bubbles: false,
 | 
						||
      })
 | 
						||
    );
 | 
						||
  });
 | 
						||
 | 
						||
  test('discard', done => {
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    element.path = '/path/to/file.txt';
 | 
						||
    assert.isOk(element.comments[0]);
 | 
						||
    element.push(
 | 
						||
      'comments',
 | 
						||
      element._newReply(
 | 
						||
        element.comments[0]!.id as UrlEncodedCommentId,
 | 
						||
        'it’s pronouced jiff, not giff'
 | 
						||
      )
 | 
						||
    );
 | 
						||
    flush();
 | 
						||
 | 
						||
    const saveOrDiscardStub = sinon.stub();
 | 
						||
    element.addEventListener('thread-changed', saveOrDiscardStub);
 | 
						||
    const draftEl = element.root?.querySelectorAll('gr-comment')[1];
 | 
						||
    assert.ok(draftEl);
 | 
						||
    draftEl!.addEventListener('comment-discard', () => {
 | 
						||
      const drafts = element.comments.filter(c => isDraft(c));
 | 
						||
      assert.equal(drafts.length, 0);
 | 
						||
      assert.isTrue(saveOrDiscardStub.called);
 | 
						||
      assert.equal(
 | 
						||
        saveOrDiscardStub.lastCall.args[0].detail.rootId,
 | 
						||
        element.rootId
 | 
						||
      );
 | 
						||
      assert.equal(
 | 
						||
        saveOrDiscardStub.lastCall.args[0].detail.path,
 | 
						||
        element.path
 | 
						||
      );
 | 
						||
      done();
 | 
						||
    });
 | 
						||
    draftEl!.dispatchEvent(
 | 
						||
      new CustomEvent('comment-discard', {
 | 
						||
        detail: {comment: draftEl!.comment},
 | 
						||
        composed: true,
 | 
						||
        bubbles: false,
 | 
						||
      })
 | 
						||
    );
 | 
						||
  });
 | 
						||
 | 
						||
  test('discard with a single comment still fires event with previous rootId', done => {
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    element.path = '/path/to/file.txt';
 | 
						||
    element.comments = [];
 | 
						||
    element.addOrEditDraft(1 as LineNumber);
 | 
						||
    flush();
 | 
						||
    const rootId = element.rootId;
 | 
						||
    assert.isOk(rootId);
 | 
						||
 | 
						||
    const saveOrDiscardStub = sinon.stub();
 | 
						||
    element.addEventListener('thread-changed', saveOrDiscardStub);
 | 
						||
    const draftEl = element.root?.querySelectorAll('gr-comment')[0];
 | 
						||
    assert.ok(draftEl);
 | 
						||
    draftEl!.addEventListener('comment-discard', () => {
 | 
						||
      assert.equal(element.comments.length, 0);
 | 
						||
      assert.isTrue(saveOrDiscardStub.called);
 | 
						||
      assert.equal(saveOrDiscardStub.lastCall.args[0].detail.rootId, rootId);
 | 
						||
      assert.equal(
 | 
						||
        saveOrDiscardStub.lastCall.args[0].detail.path,
 | 
						||
        element.path
 | 
						||
      );
 | 
						||
      done();
 | 
						||
    });
 | 
						||
    draftEl!.dispatchEvent(
 | 
						||
      new CustomEvent('comment-discard', {
 | 
						||
        detail: {comment: draftEl!.comment},
 | 
						||
        composed: true,
 | 
						||
        bubbles: false,
 | 
						||
      })
 | 
						||
    );
 | 
						||
  });
 | 
						||
 | 
						||
  test('first editing comment does not add __otherEditing attribute', () => {
 | 
						||
    element.comments = [
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter',
 | 
						||
          email: ('tenn1sballchaser@aol.com' as EmailAddress) as EmailAddress,
 | 
						||
        },
 | 
						||
        id: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
        line: 5,
 | 
						||
        path: 'test',
 | 
						||
        message: 'is this a crossover episode!?',
 | 
						||
        updated: '2015-12-08 19:48:33.843000000' as Timestamp,
 | 
						||
        __draft: true,
 | 
						||
      },
 | 
						||
    ];
 | 
						||
 | 
						||
    const replyBtn = element.$.replyBtn;
 | 
						||
    tap(replyBtn);
 | 
						||
    flush();
 | 
						||
 | 
						||
    const editing = element._orderedComments.filter(c => c.__editing === true);
 | 
						||
    assert.equal(editing.length, 1);
 | 
						||
    assert.equal(!!editing[0].__otherEditing, false);
 | 
						||
  });
 | 
						||
 | 
						||
  test(
 | 
						||
    'When not editing other comments, local storage not set' + ' after discard',
 | 
						||
    done => {
 | 
						||
      element.changeNum = 42 as NumericChangeId;
 | 
						||
      element.patchNum = 1 as PatchSetNum;
 | 
						||
      element.comments = [
 | 
						||
        {
 | 
						||
          author: {
 | 
						||
            name: 'Mr. Peanutbutter',
 | 
						||
            email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
          },
 | 
						||
          id: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
          path: 'test',
 | 
						||
          line: 5,
 | 
						||
          message: 'is this a crossover episode!?',
 | 
						||
          updated: '2015-12-08 19:48:31.843000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          author: {
 | 
						||
            name: 'Mr. Peanutbutter',
 | 
						||
            email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
          },
 | 
						||
          __draftID: '1',
 | 
						||
          in_reply_to: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
          path: 'test',
 | 
						||
          line: 5,
 | 
						||
          message: 'yes',
 | 
						||
          updated: '2015-12-08 19:48:32.843000000' as Timestamp,
 | 
						||
          __draft: true,
 | 
						||
          __editing: true,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          author: {
 | 
						||
            name: 'Mr. Peanutbutter',
 | 
						||
            email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
          },
 | 
						||
          __draftID: '2',
 | 
						||
          in_reply_to: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
          path: 'test',
 | 
						||
          line: 5,
 | 
						||
          message: 'no',
 | 
						||
          updated: '2015-12-08 19:48:33.843000000' as Timestamp,
 | 
						||
          __draft: true,
 | 
						||
        },
 | 
						||
      ];
 | 
						||
      const storageStub = sinon.stub(element.$.storage, 'setDraftComment');
 | 
						||
      flush();
 | 
						||
 | 
						||
      const draftEl = element.root?.querySelectorAll('gr-comment')[1];
 | 
						||
      assert.ok(draftEl);
 | 
						||
      draftEl!.addEventListener('comment-discard', () => {
 | 
						||
        assert.isFalse(storageStub.called);
 | 
						||
        storageStub.restore();
 | 
						||
        done();
 | 
						||
      });
 | 
						||
      draftEl!.dispatchEvent(
 | 
						||
        new CustomEvent('comment-discard', {
 | 
						||
          detail: {comment: draftEl!.comment},
 | 
						||
          composed: true,
 | 
						||
          bubbles: false,
 | 
						||
        })
 | 
						||
      );
 | 
						||
    }
 | 
						||
  );
 | 
						||
 | 
						||
  test('comment-update', () => {
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    const updatedComment = {
 | 
						||
      id: element.comments[0].id,
 | 
						||
      foo: 'bar',
 | 
						||
    };
 | 
						||
    assert.isOk(commentEl);
 | 
						||
    commentEl!.dispatchEvent(
 | 
						||
      new CustomEvent('comment-update', {
 | 
						||
        detail: {comment: updatedComment},
 | 
						||
        composed: true,
 | 
						||
        bubbles: true,
 | 
						||
      })
 | 
						||
    );
 | 
						||
    assert.strictEqual(element.comments[0], updatedComment);
 | 
						||
  });
 | 
						||
 | 
						||
  suite('jack and sally comment data test consolidation', () => {
 | 
						||
    setup(() => {
 | 
						||
      element.comments = [
 | 
						||
        {
 | 
						||
          id: 'jacks_reply' as UrlEncodedCommentId,
 | 
						||
          message: 'i like you, too',
 | 
						||
          in_reply_to: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          updated: '2015-12-25 15:00:20.396000000' as Timestamp,
 | 
						||
          unresolved: false,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_confession' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'nonexistent_comment' as UrlEncodedCommentId,
 | 
						||
          message: 'i like you, jack',
 | 
						||
          updated: '2015-12-24 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sally_to_dr_finklestein' as UrlEncodedCommentId,
 | 
						||
          in_reply_to: 'nonexistent_comment' as UrlEncodedCommentId,
 | 
						||
          message: 'i’m running away',
 | 
						||
          updated: '2015-10-31 09:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
        {
 | 
						||
          id: 'sallys_defiance' as UrlEncodedCommentId,
 | 
						||
          message: 'i will poison you so i can get away',
 | 
						||
          updated: '2015-10-31 15:00:20.396000000' as Timestamp,
 | 
						||
        },
 | 
						||
      ];
 | 
						||
    });
 | 
						||
 | 
						||
    test('orphan replies', () => {
 | 
						||
      assert.equal(4, element._orderedComments.length);
 | 
						||
    });
 | 
						||
 | 
						||
    test('keyboard shortcuts', () => {
 | 
						||
      const expandCollapseStub = sinon.stub(element, '_expandCollapseComments');
 | 
						||
      pressAndReleaseKeyOn(element, 69, null, 'e');
 | 
						||
      assert.isTrue(expandCollapseStub.lastCall.calledWith(false));
 | 
						||
 | 
						||
      pressAndReleaseKeyOn(element, 69, 'shift', 'e');
 | 
						||
      assert.isTrue(expandCollapseStub.lastCall.calledWith(true));
 | 
						||
    });
 | 
						||
 | 
						||
    test('comment in_reply_to is either null or most recent comment', () => {
 | 
						||
      element._createReplyComment('dummy', true);
 | 
						||
      flush();
 | 
						||
      assert.equal(element._orderedComments.length, 5);
 | 
						||
      assert.equal(
 | 
						||
        element._orderedComments[4].in_reply_to,
 | 
						||
        'jacks_reply' as UrlEncodedCommentId
 | 
						||
      );
 | 
						||
    });
 | 
						||
 | 
						||
    test('resolvable comments', () => {
 | 
						||
      assert.isFalse(element.unresolved);
 | 
						||
      element._createReplyComment('dummy', true, true);
 | 
						||
      flush();
 | 
						||
      assert.isTrue(element.unresolved);
 | 
						||
    });
 | 
						||
 | 
						||
    test('_setInitialExpandedState with unresolved', () => {
 | 
						||
      element.unresolved = true;
 | 
						||
      element._setInitialExpandedState();
 | 
						||
      for (let i = 0; i < element.comments.length; i++) {
 | 
						||
        assert.isFalse(element.comments[i].collapsed);
 | 
						||
      }
 | 
						||
    });
 | 
						||
 | 
						||
    test('_setInitialExpandedState without unresolved', () => {
 | 
						||
      element.unresolved = false;
 | 
						||
      element._setInitialExpandedState();
 | 
						||
      for (let i = 0; i < element.comments.length; i++) {
 | 
						||
        assert.isTrue(element.comments[i].collapsed);
 | 
						||
      }
 | 
						||
    });
 | 
						||
 | 
						||
    test('_setInitialExpandedState with robot_ids', () => {
 | 
						||
      for (let i = 0; i < element.comments.length; i++) {
 | 
						||
        (element.comments[i] as UIRobot).robot_id = '123' as RobotId;
 | 
						||
      }
 | 
						||
      element._setInitialExpandedState();
 | 
						||
      for (let i = 0; i < element.comments.length; i++) {
 | 
						||
        assert.isFalse(element.comments[i].collapsed);
 | 
						||
      }
 | 
						||
    });
 | 
						||
 | 
						||
    test('_setInitialExpandedState with collapsed state', () => {
 | 
						||
      element.comments[0].collapsed = false;
 | 
						||
      element.unresolved = false;
 | 
						||
      element._setInitialExpandedState();
 | 
						||
      assert.isFalse(element.comments[0].collapsed);
 | 
						||
      for (let i = 1; i < element.comments.length; i++) {
 | 
						||
        assert.isTrue(element.comments[i].collapsed);
 | 
						||
      }
 | 
						||
    });
 | 
						||
  });
 | 
						||
 | 
						||
  test('_computeHostClass', () => {
 | 
						||
    assert.equal(element._computeHostClass(true), 'unresolved');
 | 
						||
    assert.equal(element._computeHostClass(false), '');
 | 
						||
  });
 | 
						||
 | 
						||
  test('addDraft sets unresolved state correctly', () => {
 | 
						||
    let unresolved = true;
 | 
						||
    element.comments = [];
 | 
						||
    element.addDraft(undefined, undefined, unresolved);
 | 
						||
    assert.equal(element.comments[0].unresolved, true);
 | 
						||
 | 
						||
    unresolved = false; // comment should get added as actually resolved.
 | 
						||
    element.comments = [];
 | 
						||
    element.addDraft(undefined, undefined, unresolved);
 | 
						||
    assert.equal(element.comments[0].unresolved, false);
 | 
						||
 | 
						||
    element.comments = [];
 | 
						||
    element.addDraft();
 | 
						||
    assert.equal(element.comments[0].unresolved, true);
 | 
						||
  });
 | 
						||
 | 
						||
  test('_newDraft with root', () => {
 | 
						||
    const draft = element._newDraft();
 | 
						||
    assert.equal(draft.patch_set, 3 as PatchSetNum);
 | 
						||
  });
 | 
						||
 | 
						||
  test('_newDraft with no root', () => {
 | 
						||
    element.comments = [];
 | 
						||
    element.diffSide = Side.RIGHT;
 | 
						||
    element.patchNum = 2 as PatchSetNum;
 | 
						||
    const draft = element._newDraft();
 | 
						||
    assert.equal(draft.patch_set, 2 as PatchSetNum);
 | 
						||
  });
 | 
						||
 | 
						||
  test('new comment gets created', () => {
 | 
						||
    element.comments = [];
 | 
						||
    element.addOrEditDraft(1);
 | 
						||
    assert.equal(element.comments.length, 1);
 | 
						||
    // Mock a submitted comment.
 | 
						||
    element.comments[0].id = (element.comments[0] as UIDraft)
 | 
						||
      .__draftID as UrlEncodedCommentId;
 | 
						||
    delete (element.comments[0] as UIDraft).__draft;
 | 
						||
    element.addOrEditDraft(1);
 | 
						||
    assert.equal(element.comments.length, 2);
 | 
						||
  });
 | 
						||
 | 
						||
  test('unresolved label', () => {
 | 
						||
    element.unresolved = false;
 | 
						||
    const label = element.shadowRoot?.querySelector('#unresolvedLabel');
 | 
						||
    assert.isOk(label);
 | 
						||
    assert.isTrue(label!.hasAttribute('hidden'));
 | 
						||
    element.unresolved = true;
 | 
						||
    assert.isFalse(label!.hasAttribute('hidden'));
 | 
						||
  });
 | 
						||
 | 
						||
  test('draft comments are at the end of orderedComments', () => {
 | 
						||
    element.comments = [
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter',
 | 
						||
          email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
        },
 | 
						||
        id: '2' as UrlEncodedCommentId,
 | 
						||
        line: 5,
 | 
						||
        message: 'Earlier draft',
 | 
						||
        updated: '2015-12-08 19:48:33.843000000' as Timestamp,
 | 
						||
        __draft: true,
 | 
						||
      },
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter2',
 | 
						||
          email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
        },
 | 
						||
        id: '1' as UrlEncodedCommentId,
 | 
						||
        line: 5,
 | 
						||
        message: 'This comment was left last but is not a draft',
 | 
						||
        updated: '2015-12-10 19:48:33.843000000' as Timestamp,
 | 
						||
      },
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter2',
 | 
						||
          email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
        },
 | 
						||
        id: '3' as UrlEncodedCommentId,
 | 
						||
        line: 5,
 | 
						||
        message: 'Later draft',
 | 
						||
        updated: '2015-12-09 19:48:33.843000000' as Timestamp,
 | 
						||
        __draft: true,
 | 
						||
      },
 | 
						||
    ];
 | 
						||
    assert.equal(element._orderedComments[0].id, '1' as UrlEncodedCommentId);
 | 
						||
    assert.equal(element._orderedComments[1].id, '2' as UrlEncodedCommentId);
 | 
						||
    assert.equal(element._orderedComments[2].id, '3' as UrlEncodedCommentId);
 | 
						||
  });
 | 
						||
 | 
						||
  test('reflects lineNum and commentSide to attributes', () => {
 | 
						||
    element.lineNum = 7;
 | 
						||
    element.diffSide = Side.LEFT;
 | 
						||
 | 
						||
    assert.equal(element.getAttribute('line-num'), '7');
 | 
						||
    assert.equal(element.getAttribute('diff-side'), Side.LEFT);
 | 
						||
  });
 | 
						||
 | 
						||
  test('reflects range to JSON serialized attribute if set', () => {
 | 
						||
    element.range = {
 | 
						||
      start_line: 4,
 | 
						||
      end_line: 5,
 | 
						||
      start_character: 6,
 | 
						||
      end_character: 7,
 | 
						||
    };
 | 
						||
 | 
						||
    assert.isOk(element.getAttribute('range'));
 | 
						||
    assert.deepEqual(JSON.parse(element.getAttribute('range')!), {
 | 
						||
      start_line: 4,
 | 
						||
      end_line: 5,
 | 
						||
      start_character: 6,
 | 
						||
      end_character: 7,
 | 
						||
    });
 | 
						||
  });
 | 
						||
 | 
						||
  test('removes range attribute if range is unset', () => {
 | 
						||
    element.range = {
 | 
						||
      start_line: 4,
 | 
						||
      end_line: 5,
 | 
						||
      start_character: 6,
 | 
						||
      end_character: 7,
 | 
						||
    };
 | 
						||
    element.range = undefined;
 | 
						||
 | 
						||
    assert.notOk(element.hasAttribute('range'));
 | 
						||
  });
 | 
						||
});
 | 
						||
 | 
						||
suite('comment action tests on resolved comments', () => {
 | 
						||
  let element: GrCommentThread;
 | 
						||
 | 
						||
  setup(() => {
 | 
						||
    stub('gr-rest-api-interface', {
 | 
						||
      getLoggedIn() {
 | 
						||
        return Promise.resolve(false);
 | 
						||
      },
 | 
						||
      saveDiffDraft() {
 | 
						||
        return Promise.resolve(({
 | 
						||
          ok: true,
 | 
						||
          text() {
 | 
						||
            return Promise.resolve(
 | 
						||
              ")]}'\n" +
 | 
						||
                JSON.stringify({
 | 
						||
                  id: '7afa4931_de3d65bd',
 | 
						||
                  path: '/path/to/file.txt',
 | 
						||
                  line: 5,
 | 
						||
                  in_reply_to: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
                  updated: '2015-12-21 02:01:10.850000000',
 | 
						||
                  message: 'Done',
 | 
						||
                })
 | 
						||
            );
 | 
						||
          },
 | 
						||
        } as unknown) as Response);
 | 
						||
      },
 | 
						||
      deleteDiffDraft() {
 | 
						||
        return Promise.resolve(({ok: true} as unknown) as Response);
 | 
						||
      },
 | 
						||
    });
 | 
						||
    element = withCommentFixture.instantiate();
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
    element.changeNum = 1 as NumericChangeId;
 | 
						||
    element.comments = [
 | 
						||
      {
 | 
						||
        author: {
 | 
						||
          name: 'Mr. Peanutbutter',
 | 
						||
          email: 'tenn1sballchaser@aol.com' as EmailAddress,
 | 
						||
        },
 | 
						||
        id: 'baf0414d_60047215' as UrlEncodedCommentId,
 | 
						||
        line: 5,
 | 
						||
        message: 'is this a crossover episode!?',
 | 
						||
        updated: '2015-12-08 19:48:33.843000000' as Timestamp,
 | 
						||
        path: '/path/to/file.txt',
 | 
						||
        unresolved: false,
 | 
						||
      },
 | 
						||
    ];
 | 
						||
    flush();
 | 
						||
  });
 | 
						||
 | 
						||
  test('ack and done should be hidden', () => {
 | 
						||
    element.changeNum = 42 as NumericChangeId;
 | 
						||
    element.patchNum = 1 as PatchSetNum;
 | 
						||
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const ackBtn = element.shadowRoot?.querySelector('#ackBtn');
 | 
						||
    const doneBtn = element.shadowRoot?.querySelector('#doneBtn');
 | 
						||
    assert.equal(ackBtn, null);
 | 
						||
    assert.equal(doneBtn, null);
 | 
						||
  });
 | 
						||
 | 
						||
  test('reply and quote button should be visible', () => {
 | 
						||
    const commentEl = element.shadowRoot?.querySelector('gr-comment');
 | 
						||
    assert.ok(commentEl);
 | 
						||
 | 
						||
    const replyBtn = element.shadowRoot?.querySelector('#replyBtn');
 | 
						||
    const quoteBtn = element.shadowRoot?.querySelector('#quoteBtn');
 | 
						||
    assert.ok(replyBtn);
 | 
						||
    assert.ok(quoteBtn);
 | 
						||
  });
 | 
						||
});
 |