Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/static_src/elements/framework/mr-comment-content/mr-attachment.test.js b/static_src/elements/framework/mr-comment-content/mr-attachment.test.js
new file mode 100644
index 0000000..ec79c66
--- /dev/null
+++ b/static_src/elements/framework/mr-comment-content/mr-attachment.test.js
@@ -0,0 +1,228 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {assert, expect} from 'chai';
+import {MrAttachment} from './mr-attachment.js';
+import {prpcClient} from 'prpc-client-instance.js';
+import {FILE_DOWNLOAD_WARNING} from 'shared/settings.js';
+
+let element;
+
+describe('mr-attachment', () => {
+  beforeEach(() => {
+    element = document.createElement('mr-attachment');
+    document.body.appendChild(element);
+    sinon.stub(prpcClient, 'call').returns(Promise.resolve({}));
+  });
+
+  afterEach(() => {
+    document.body.removeChild(element);
+    prpcClient.call.restore();
+  });
+
+  it('initializes', () => {
+    assert.instanceOf(element, MrAttachment);
+  });
+
+  it('shows image thumbnail', async () => {
+    element.attachment = {
+      thumbnailUrl: 'thumbnail.jpeg',
+      contentType: 'image/jpeg',
+    };
+    await element.updateComplete;
+    const img = element.shadowRoot.querySelector('img');
+    assert.isNotNull(img);
+    assert.isTrue(img.src.endsWith('thumbnail.jpeg'));
+  });
+
+  it('shows video thumbnail', async () => {
+    element.attachment = {
+      viewUrl: 'video.mp4',
+      contentType: 'video/mpeg',
+    };
+    await element.updateComplete;
+    const video = element.shadowRoot.querySelector('video');
+    assert.isNotNull(video);
+    assert.isTrue(video.src.endsWith('video.mp4'));
+  });
+
+  it('does not show image thumbnail if deleted', async () => {
+    element.attachment = {
+      thumbnailUrl: 'thumbnail.jpeg',
+      contentType: 'image/jpeg',
+      isDeleted: true,
+    };
+    await element.updateComplete;
+    const img = element.shadowRoot.querySelector('img');
+    assert.isNull(img);
+  });
+
+  it('does not show video thumbnail if deleted', async () => {
+    element.attachment = {
+      viewUrl: 'video.mp4',
+      contentType: 'video/mpeg',
+      isDeleted: true,
+    };
+    await element.updateComplete;
+    const video = element.shadowRoot.querySelector('video');
+    assert.isNull(video);
+  });
+
+  it('deletes attachment', async () => {
+    prpcClient.call.callsFake(() => Promise.resolve({}));
+
+    element.attachment = {
+      attachmentId: 67890,
+      isDeleted: false,
+    };
+    element.canDelete = true;
+    element.projectName = 'proj';
+    element.localId = 1234;
+    element.sequenceNum = 3;
+    await element.updateComplete;
+
+    const deleteButton = element.shadowRoot.querySelector('chops-button');
+    deleteButton.click();
+
+    assert.deepEqual(prpcClient.call.getCall(0).args, [
+      'monorail.Issues', 'DeleteAttachment',
+      {
+        issueRef: {
+          projectName: 'proj',
+          localId: 1234,
+        },
+        sequenceNum: 3,
+        attachmentId: 67890,
+        delete: true,
+      },
+    ]);
+    assert.isTrue(prpcClient.call.calledOnce);
+  });
+
+  it('undeletes attachment', async () => {
+    prpcClient.call.callsFake(() => Promise.resolve({}));
+    element.attachment = {
+      attachmentId: 67890,
+      isDeleted: true,
+    };
+    element.canDelete = true;
+    element.projectName = 'proj';
+    element.localId = 1234;
+    element.sequenceNum = 3;
+    await element.updateComplete;
+
+    const deleteButton = element.shadowRoot.querySelector('chops-button');
+    deleteButton.click();
+
+    assert.deepEqual(prpcClient.call.getCall(0).args, [
+      'monorail.Issues', 'DeleteAttachment',
+      {
+        issueRef: {
+          projectName: 'proj',
+          localId: 1234,
+        },
+        sequenceNum: 3,
+        attachmentId: 67890,
+        delete: false,
+      },
+    ]);
+    assert.isTrue(prpcClient.call.calledOnce);
+  });
+
+  it('view link is not displayed if not given', async () => {
+    element.attachment = {};
+    await element.updateComplete;
+    const viewLink = element.shadowRoot.querySelector('.attachment-view');
+    assert.isNull(viewLink);
+  });
+
+  it('view link is displayed if given', async () => {
+    element.attachment = {
+      viewUrl: 'http://example.com/attachment.foo',
+    };
+    await element.updateComplete;
+    const viewLink = element.shadowRoot.querySelector('.attachment-view');
+    assert.isNotNull(viewLink);
+    expect(viewLink).to.be.displayed;
+    assert.equal(viewLink.href, 'http://example.com/attachment.foo');
+  });
+
+  describe('download', () => {
+    let downloadLink;
+
+    beforeEach(async () => {
+      sinon.stub(window, 'confirm').returns(false);
+
+
+      element.attachment = {};
+      await element.updateComplete;
+      downloadLink = element.shadowRoot.querySelector('.attachment-download');
+      // Prevent Karma from opening up new tabs because of simulated link
+      // clicks.
+      downloadLink.removeAttribute('target');
+    });
+
+    afterEach(() => {
+      window.confirm.restore();
+    });
+
+    it('download link is not displayed if not given', async () => {
+      element.attachment = {};
+      await element.updateComplete;
+      assert.isTrue(downloadLink.hidden);
+    });
+
+    it('download link is displayed if given', async () => {
+      element.attachment = {
+        downloadUrl: 'http://example.com/attachment.foo',
+      };
+      await element.updateComplete;
+      const downloadLink = element.shadowRoot.querySelector(
+          '.attachment-download');
+      assert.isFalse(downloadLink.hidden);
+      expect(downloadLink).to.be.displayed;
+      assert.equal(downloadLink.href, 'http://example.com/attachment.foo');
+    });
+
+    it('download allows recognized file extension and type', async () => {
+      element.attachment = {
+        contentType: 'image/png',
+        filename: 'not-a-virus.png',
+        downloadUrl: '#',
+      };
+      await element.updateComplete;
+
+      downloadLink.click();
+
+      sinon.assert.notCalled(window.confirm);
+    });
+
+    it('file extension matching is case insensitive', async () => {
+      element.attachment = {
+        contentType: 'image/png',
+        filename: 'not-a-virus.PNG',
+        downloadUrl: '#',
+      };
+      await element.updateComplete;
+
+      downloadLink.click();
+
+      sinon.assert.notCalled(window.confirm);
+    });
+
+    it('download warns on unrecognized file extension and type', async () => {
+      element.attachment = {
+        contentType: 'application/virus',
+        filename: 'fake-virus.exe',
+        downloadUrl: '#',
+      };
+      await element.updateComplete;
+
+      downloadLink.click();
+
+      sinon.assert.calledOnce(window.confirm);
+      sinon.assert.calledWith(window.confirm, FILE_DOWNLOAD_WARNING);
+    });
+  });
+});