| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import {assert} from 'chai'; |
| import sinon from 'sinon'; |
| |
| import {MrPhase} from './mr-phase.js'; |
| |
| |
| let element; |
| |
| describe('mr-phase', () => { |
| beforeEach(() => { |
| element = document.createElement('mr-phase'); |
| document.body.appendChild(element); |
| }); |
| |
| afterEach(() => { |
| document.body.removeChild(element); |
| }); |
| |
| it('initializes', () => { |
| assert.instanceOf(element, MrPhase); |
| }); |
| |
| it('clicking edit button opens edit dialog', async () => { |
| element.phaseName = 'Beta'; |
| |
| await element.updateComplete; |
| |
| const editDialog = element.querySelector('#editPhase'); |
| assert.isFalse(editDialog.opened); |
| |
| element.querySelector('.phase-edit').click(); |
| |
| await element.updateComplete; |
| |
| assert.isTrue(editDialog.opened); |
| }); |
| |
| it('discarding form changes closes dialog', async () => { |
| await element.updateComplete; |
| |
| // Open the edit dialog. |
| element.edit(); |
| const editDialog = element.querySelector('#editPhase'); |
| const editForm = element.querySelector('#metadataForm'); |
| |
| await element.updateComplete; |
| |
| assert.isTrue(editDialog.opened); |
| editForm.discard(); |
| |
| await element.updateComplete; |
| |
| assert.isFalse(editDialog.opened); |
| }); |
| |
| describe('milestone fetching', () => { |
| beforeEach(() => { |
| sinon.stub(element, 'fetchMilestoneData'); |
| }); |
| |
| it('_launchedMilestone extracts M-Launched for phase', () => { |
| element._fieldValueMap = new Map([['m-launched beta', ['87']]]); |
| element.phaseName = 'Beta'; |
| |
| assert.equal(element._launchedMilestone, '87'); |
| assert.equal(element._approvedMilestone, undefined); |
| assert.equal(element._targetMilestone, undefined); |
| }); |
| |
| it('_approvedMilestone extracts M-Approved for phase', () => { |
| element._fieldValueMap = new Map([['m-approved beta', ['86']]]); |
| element.phaseName = 'Beta'; |
| |
| assert.equal(element._launchedMilestone, undefined); |
| assert.equal(element._approvedMilestone, '86'); |
| assert.equal(element._targetMilestone, undefined); |
| }); |
| |
| it('_targetMilestone extracts M-Target for phase', () => { |
| element._fieldValueMap = new Map([['m-target beta', ['85']]]); |
| element.phaseName = 'Beta'; |
| |
| assert.equal(element._launchedMilestone, undefined); |
| assert.equal(element._approvedMilestone, undefined); |
| assert.equal(element._targetMilestone, '85'); |
| }); |
| |
| it('_milestoneToFetch returns empty when no relevant milestone', () => { |
| element._fieldValueMap = new Map([['m-target beta', ['85']]]); |
| element.phaseName = 'Stable'; |
| |
| assert.equal(element._milestoneToFetch, ''); |
| }); |
| |
| it('_milestoneToFetch selects highest milestone', () => { |
| element._fieldValueMap = new Map([ |
| ['m-target beta', ['84']], |
| ['m-approved beta', ['85']], |
| ['m-launched beta', ['86']]]); |
| element.phaseName = 'Beta'; |
| |
| assert.equal(element._milestoneToFetch, '86'); |
| }); |
| |
| it('does not fetch when no milestones specified', async () => { |
| element.issue = {projectName: 'chromium', localId: 12}; |
| |
| await element.updateComplete; |
| |
| sinon.assert.notCalled(element.fetchMilestoneData); |
| }); |
| |
| it('does not fetch when milestone to fetch is unchanged', async () => { |
| element._fetchedMilestone = '86'; |
| element._fieldValueMap = new Map([['m-target beta', ['86']]]); |
| element.phaseName = 'Beta'; |
| |
| await element.updateComplete; |
| |
| sinon.assert.notCalled(element.fetchMilestoneData); |
| }); |
| |
| it('fetches when milestone found', async () => { |
| element._fetchedMilestone = undefined; |
| element._fieldValueMap = new Map([['m-target beta', ['86']]]); |
| element.phaseName = 'Beta'; |
| |
| await element.updateComplete; |
| |
| sinon.assert.calledWith(element.fetchMilestoneData, '86'); |
| }); |
| |
| it('re-fetches when new milestone found', async () => { |
| element._fetchedMilestone = '86'; |
| element._fieldValueMap = new Map([ |
| ['m-target beta', ['86']], |
| ['m-launched beta', ['87']]]); |
| element.phaseName = 'Beta'; |
| |
| await element.updateComplete; |
| |
| sinon.assert.calledWith(element.fetchMilestoneData, '87'); |
| }); |
| |
| it('re-fetches only after last stale fetch finishes', async () => { |
| element._fetchedMilestone = '84'; |
| element._fieldValueMap = new Map([['m-target beta', ['86']]]); |
| element.phaseName = 'Beta'; |
| element._isFetchingMilestone = true; |
| |
| await element.updateComplete; |
| |
| sinon.assert.notCalled(element.fetchMilestoneData); |
| |
| // Previous in flight fetch finishes. |
| element._fetchedMilestone = '85'; |
| element._isFetchingMilestone = false; |
| |
| await element.updateComplete; |
| |
| sinon.assert.calledWith(element.fetchMilestoneData, '86'); |
| }); |
| }); |
| |
| describe('milestone fetching with fake server responses', () => { |
| beforeEach(() => { |
| sinon.stub(window, 'fetch'); |
| sinon.spy(element, 'fetchMilestoneData'); |
| }); |
| |
| afterEach(() => { |
| window.fetch.restore(); |
| }); |
| |
| it('does not refetch when server response finishes', async () => { |
| const response = new window.Response('{"mstones": [{"mstone": 86}]}', { |
| status: 200, |
| headers: { |
| 'Content-type': 'application/json', |
| }, |
| }); |
| |
| window.fetch.returns(Promise.resolve(response)); |
| |
| element._fieldValueMap = new Map([['m-target beta', ['86']]]); |
| element.phaseName = 'Beta'; |
| |
| await element.updateComplete; |
| |
| sinon.assert.calledWith(element.fetchMilestoneData, '86'); |
| |
| assert.isTrue(element._isFetchingMilestone); |
| |
| await element._fetchMilestoneComplete; |
| |
| assert.deepEqual(element._milestoneData, {'mstones': [{'mstone': 86}]}); |
| assert.equal(element._fetchedMilestone, '86'); |
| assert.isFalse(element._isFetchingMilestone); |
| |
| await element.updateComplete; |
| |
| sinon.assert.calledOnce(element.fetchMilestoneData); |
| }); |
| }); |
| }); |