/** * @license * Copyright (C) 2017 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-repo-detail-list.js'; import 'lodash/lodash.js'; import {page} from '../../../utils/page-wrapper-utils.js'; import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js'; const basicFixture = fixtureFromElement('gr-repo-detail-list'); let counter; const branchGenerator = () => { return { ref: `refs/heads/test${++counter}`, revision: '9c9d08a438e55e52f33b608415e6dddd9b18550d', web_links: [ { name: 'diffusion', url: `https://git.example.org/branch/test;refs/heads/test${counter}`, }, ], }; }; const tagGenerator = () => { return { ref: `refs/tags/test${++counter}`, revision: '9c9d08a438e55e52f33b608415e6dddd9b18550d', web_links: [ { name: 'diffusion', url: `https://git.example.org/tag/test;refs/tags/test${counter}`, }, ], message: 'Annotated tag', tagger: { name: 'Test User', email: 'test.user@gmail.com', date: '2017-09-19 14:54:00.000000000', tz: 540, }, }; }; suite('gr-repo-detail-list', () => { suite('Branches', () => { let element; let branches; setup(() => { element = basicFixture.instantiate(); element.detailType = 'branches'; counter = 0; sinon.stub(page, 'show'); }); suite('list of repo branches', () => { setup(done => { branches = [{ ref: 'HEAD', revision: 'master', }].concat(_.times(25, branchGenerator)); stub('gr-rest-api-interface', { getRepoBranches(num, project, offset) { return Promise.resolve(branches); }, }); const params = { repo: 'test', detail: 'branches', }; element._paramsChanged(params).then(() => { flush(done); }); }); test('test for branch in the list', done => { flush(() => { assert.equal(element._items[2].ref, 'refs/heads/test2'); done(); }); }); test('test for web links in the branches list', done => { flush(() => { assert.equal(element._items[2].web_links[0].url, 'https://git.example.org/branch/test;refs/heads/test2'); done(); }); }); test('test for refs/heads/ being striped from ref', done => { flush(() => { assert.equal(element._stripRefs(element._items[2].ref, element.detailType), 'test2'); done(); }); }); test('_shownItems', () => { assert.equal(element._shownItems.length, 25); }); test('Edit HEAD button not admin', done => { sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true)); sinon.stub(element.restApiService, 'getRepoAccess').returns( Promise.resolve({ test: {is_owner: false}, })); element._determineIfOwner('test').then(() => { assert.equal(element._isOwner, false); assert.equal(getComputedStyle(dom(element.root) .querySelector('.revisionNoEditing')).display, 'inline'); assert.equal(getComputedStyle(dom(element.root) .querySelector('.revisionEdit')).display, 'none'); done(); }); }); test('Edit HEAD button admin', done => { const saveBtn = element.root.querySelector('.saveBtn'); const cancelBtn = element.root.querySelector('.cancelBtn'); const editBtn = element.root.querySelector('.editBtn'); const revisionNoEditing = dom(element.root) .querySelector('.revisionNoEditing'); const revisionWithEditing = dom(element.root) .querySelector('.revisionWithEditing'); sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true)); sinon.stub(element.restApiService, 'getRepoAccess').returns( Promise.resolve({ test: {is_owner: true}, })); sinon.stub(element, '_handleSaveRevision'); element._determineIfOwner('test').then(() => { assert.equal(element._isOwner, true); // The revision container for non-editing enabled row is not visible. assert.equal(getComputedStyle(revisionNoEditing).display, 'none'); // The revision container for editing enabled row is visible. assert.notEqual(getComputedStyle(dom(element.root) .querySelector('.revisionEdit')).display, 'none'); // The revision and edit button are visible. assert.notEqual(getComputedStyle(revisionWithEditing).display, 'none'); assert.notEqual(getComputedStyle(editBtn).display, 'none'); // The input, cancel, and save buttons are not visible. const hiddenElements = dom(element.root) .querySelectorAll('.canEdit .editItem'); for (const item of hiddenElements) { assert.equal(getComputedStyle(item).display, 'none'); } MockInteractions.tap(editBtn); flush(); // The revision and edit button are not visible. assert.equal(getComputedStyle(revisionWithEditing).display, 'none'); assert.equal(getComputedStyle(editBtn).display, 'none'); // The input, cancel, and save buttons are not visible. for (const item of hiddenElements) { assert.notEqual(getComputedStyle(item).display, 'none'); } // The revised ref was set correctly assert.equal(element._revisedRef, 'master'); assert.isFalse(saveBtn.disabled); // Delete the ref. element._revisedRef = ''; assert.isTrue(saveBtn.disabled); // Change the ref to something else element._revisedRef = 'newRef'; element._repo = 'test'; assert.isFalse(saveBtn.disabled); // Save button calls handleSave. since this is stubbed, the edit // section remains open. MockInteractions.tap(saveBtn); assert.isTrue(element._handleSaveRevision.called); // When cancel is tapped, the edit secion closes. MockInteractions.tap(cancelBtn); flush(); // The revision and edit button are visible. assert.notEqual(getComputedStyle(revisionWithEditing).display, 'none'); assert.notEqual(getComputedStyle(editBtn).display, 'none'); // The input, cancel, and save buttons are not visible. for (const item of hiddenElements) { assert.equal(getComputedStyle(item).display, 'none'); } done(); }); }); test('_handleSaveRevision with invalid rev', done => { const event = {model: {set: sinon.stub()}}; element._isEditing = true; sinon.stub(element.restApiService, 'setRepoHead').returns( Promise.resolve({ status: 400, }) ); element._setRepoHead('test', 'newRef', event).then(() => { assert.isTrue(element._isEditing); assert.isFalse(event.model.set.called); done(); }); }); test('_handleSaveRevision with valid rev', done => { const event = {model: {set: sinon.stub()}}; element._isEditing = true; sinon.stub(element.restApiService, 'setRepoHead').returns( Promise.resolve({ status: 200, }) ); element._setRepoHead('test', 'newRef', event).then(() => { assert.isFalse(element._isEditing); assert.isTrue(event.model.set.called); done(); }); }); test('test _computeItemName', () => { assert.deepEqual(element._computeItemName('branches'), 'Branch'); assert.deepEqual(element._computeItemName('tags'), 'Tag'); }); }); suite('list with less then 25 branches', () => { setup(done => { branches = _.times(25, branchGenerator); stub('gr-rest-api-interface', { getRepoBranches(num, repo, offset) { return Promise.resolve(branches); }, }); const params = { repo: 'test', detail: 'branches', }; element._paramsChanged(params).then(() => { flush(done); }); }); test('_shownItems', () => { assert.equal(element._shownItems.length, 25); }); }); suite('filter', () => { test('_paramsChanged', done => { sinon.stub( element.restApiService, 'getRepoBranches') .callsFake(() => Promise.resolve(branches)); const params = { detail: 'branches', repo: 'test', filter: 'test', offset: 25, }; element._paramsChanged(params).then(() => { assert.equal(element.restApiService.getRepoBranches.lastCall.args[0], 'test'); assert.equal(element.restApiService.getRepoBranches.lastCall.args[1], 'test'); assert.equal(element.restApiService.getRepoBranches.lastCall.args[2], 25); assert.equal(element.restApiService.getRepoBranches.lastCall.args[3], 25); done(); }); }); }); suite('404', () => { test('fires page-error', done => { const response = {status: 404}; sinon.stub(element.restApiService, 'getRepoBranches').callsFake( (filter, repo, reposBranchesPerPage, opt_offset, errFn) => { errFn(response); }); element.addEventListener('page-error', e => { assert.deepEqual(e.detail.response, response); done(); }); const params = { detail: 'branches', repo: 'test', filter: 'test', offset: 25, }; element._paramsChanged(params); }); }); }); suite('Tags', () => { let element; let tags; setup(() => { element = basicFixture.instantiate(); element.detailType = 'tags'; counter = 0; sinon.stub(page, 'show'); }); test('_computeMessage', () => { let message = 'v2.15-rc1↵-----BEGIN PGP SIGNATURE-----↵Version: GnuPG v' + '1↵↵iQIcBAABAgAGBQJZ27O7AAoJEF/XxZqaEoiMy6kQAMoQCpGr3J6JITI4BVWsr7QM↵xy' + 'EcWH5YPUko5EPTbkABHmaVyFmKGkuIQdn6c+NIbqJOk+5XT4oUyRSo1T569HPJ↵3kyxEJi' + 'T1ryvp5BIHwdvHx58fjw1+YkiWLZuZq1FFkUYqnWTYCrkv7Fok98pdOmV↵CL1Hgugi5uK8' + '/kxf1M7+Nv6piaZ140pwSb1h6QdAjaZVfaBCnoxlG4LRUqHvEYay↵f4QYgFT67auHIGkZ4' + 'moUcsp2Du/1jSsCWL/CPwjPFGbbckVAjLCMT9yD3NKwpEZF↵pfsiZyHI9dL0M+QjVrM+RD' + 'HwIIJwra8R0IMkDlQ6MDrFlKNqNBbo588S6UPrm71L↵YuiwWlcrK9ZIybxT6LzbR65Rvez' + 'DSitQ+xeIfpZE19/X6BCnvlARLE8k/tC2JksI↵lEZi7Lf3FQdIcwwyt98tJkS9HX9v9jbC' + '5QXifnoj3Li8tHSLuQ1dJCxHQiis6ojI↵OWUFkm0IHBXVNHA2dqYBdM+pL12mlI3wp6Ica' + '4cdEVDwzu+j1xnVSFUa+d+Y2xJF↵7mytuyhHiKG4hm+zbhMv6WD8Q3FoDsJZeLY99l0hYQ' + 'SnnkMduFVroIs45pAs8gUA↵RvYla8mm9w/543IJAPzzFarPVLSsSyQ7tJl3UBzjKRNH/rX' + 'W+F22qyWD1zyHPUIR↵C00ItmwlAvveImYKpQAH↵=L+K9↵-----END PGP SIGNATURE---' + '--'; assert.equal(element._computeMessage(message), 'v2.15-rc1↵'); message = 'v2.15-rc1'; assert.equal(element._computeMessage(message), 'v2.15-rc1'); }); suite('list of repo tags', () => { setup(done => { tags = _.times(26, tagGenerator); stub('gr-rest-api-interface', { getRepoTags(num, repo, offset) { return Promise.resolve(tags); }, }); const params = { repo: 'test', detail: 'tags', }; element._paramsChanged(params).then(() => { flush(done); }); }); test('test for tag in the list', done => { flush(() => { assert.equal(element._items[1].ref, 'refs/tags/test2'); done(); }); }); test('test for tag message in the list', done => { flush(() => { assert.equal(element._items[1].message, 'Annotated tag'); done(); }); }); test('test for tagger in the tag list', done => { const tagger = { name: 'Test User', email: 'test.user@gmail.com', date: '2017-09-19 14:54:00.000000000', tz: 540, }; flush(() => { assert.deepEqual(element._items[1].tagger, tagger); done(); }); }); test('test for web links in the tags list', done => { flush(() => { assert.equal(element._items[1].web_links[0].url, 'https://git.example.org/tag/test;refs/tags/test2'); done(); }); }); test('test for refs/tags/ being striped from ref', done => { flush(() => { assert.equal(element._stripRefs(element._items[1].ref, element.detailType), 'test2'); done(); }); }); test('_shownItems', () => { assert.equal(element._shownItems.length, 25); }); test('_computeHideTagger', () => { const testObject1 = { tagger: 'test', }; assert.equal(element._computeHideTagger(testObject1), ''); assert.equal(element._computeHideTagger(undefined), 'hide'); }); }); suite('list with less then 25 tags', () => { setup(done => { tags = _.times(25, tagGenerator); stub('gr-rest-api-interface', { getRepoTags(num, project, offset) { return Promise.resolve(tags); }, }); const params = { repo: 'test', detail: 'tags', }; element._paramsChanged(params).then(() => { flush(done); }); }); test('_shownItems', () => { assert.equal(element._shownItems.length, 25); }); }); suite('filter', () => { test('_paramsChanged', done => { sinon.stub( element.restApiService, 'getRepoTags') .callsFake(() => Promise.resolve(tags)); const params = { repo: 'test', detail: 'tags', filter: 'test', offset: 25, }; element._paramsChanged(params).then(() => { assert.equal(element.restApiService.getRepoTags.lastCall.args[0], 'test'); assert.equal(element.restApiService.getRepoTags.lastCall.args[1], 'test'); assert.equal(element.restApiService.getRepoTags.lastCall.args[2], 25); assert.equal(element.restApiService.getRepoTags.lastCall.args[3], 25); done(); }); }); }); suite('create new', () => { test('_handleCreateClicked called when create-click fired', () => { sinon.stub(element, '_handleCreateClicked'); element.shadowRoot .querySelector('gr-list-view').dispatchEvent( new CustomEvent('create-clicked', { composed: true, bubbles: true, })); assert.isTrue(element._handleCreateClicked.called); }); test('_handleCreateClicked opens modal', () => { const openStub = sinon.stub(element.$.createOverlay, 'open'); element._handleCreateClicked(); assert.isTrue(openStub.called); }); test('_handleCreateItem called when confirm fired', () => { sinon.stub(element, '_handleCreateItem'); element.$.createDialog.dispatchEvent( new CustomEvent('confirm', { composed: true, bubbles: true, })); assert.isTrue(element._handleCreateItem.called); }); test('_handleCloseCreate called when cancel fired', () => { sinon.stub(element, '_handleCloseCreate'); element.$.createDialog.dispatchEvent( new CustomEvent('cancel', { composed: true, bubbles: true, })); assert.isTrue(element._handleCloseCreate.called); }); }); suite('404', () => { test('fires page-error', done => { const response = {status: 404}; sinon.stub(element.restApiService, 'getRepoTags').callsFake( (filter, repo, reposTagsPerPage, opt_offset, errFn) => { errFn(response); }); element.addEventListener('page-error', e => { assert.deepEqual(e.detail.response, response); done(); }); const params = { repo: 'test', detail: 'tags', filter: 'test', offset: 25, }; element._paramsChanged(params); }); }); test('test _computeHideDeleteClass', () => { assert.deepEqual(element._computeHideDeleteClass(true, false), 'show'); assert.deepEqual(element._computeHideDeleteClass(false, true), 'show'); assert.deepEqual(element._computeHideDeleteClass(false, false), ''); }); }); });