diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-02 06:09:04 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-02 06:09:04 +0300 |
commit | ceb0c326ae57bac76fe40ca3471b0ee5d152f58e (patch) | |
tree | b13351e5e59f6275608b6715ed4afc98ec3c6227 /spec/frontend/boards/components | |
parent | 61a1ecc5e9a8fba5c8cfa37a67905fb71ccf4fd0 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/boards/components')
6 files changed, 0 insertions, 893 deletions
diff --git a/spec/frontend/boards/components/board_card_deprecated_spec.js b/spec/frontend/boards/components/board_card_deprecated_spec.js deleted file mode 100644 index e21a8941bdc..00000000000 --- a/spec/frontend/boards/components/board_card_deprecated_spec.js +++ /dev/null @@ -1,181 +0,0 @@ -/* global List */ -/* global ListAssignee */ -/* global ListLabel */ - -import { mount } from '@vue/test-utils'; - -import MockAdapter from 'axios-mock-adapter'; -import waitForPromises from 'helpers/wait_for_promises'; -import BoardCardDeprecated from '~/boards/components/board_card_deprecated.vue'; -import issueCardInner from '~/boards/components/issue_card_inner_deprecated.vue'; -import store from '~/boards/stores'; -import boardsStore from '~/boards/stores/boards_store'; -import axios from '~/lib/utils/axios_utils'; - -import sidebarEventHub from '~/sidebar/event_hub'; -import '~/boards/models/label'; -import '~/boards/models/assignee'; -import '~/boards/models/list'; -import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; -import { listObj, boardsMockInterceptor, setMockEndpoints } from '../mock_data'; - -describe('BoardCard', () => { - let wrapper; - let mock; - let list; - - const findIssueCardInner = () => wrapper.find(issueCardInner); - const findUserAvatarLink = () => wrapper.find(userAvatarLink); - - // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized - const mountComponent = (propsData) => { - wrapper = mount(BoardCardDeprecated, { - stubs: { - issueCardInner, - }, - store, - propsData: { - list, - issue: list.issues[0], - disabled: false, - index: 0, - ...propsData, - }, - provide: { - groupId: null, - rootPath: '/', - scopedLabelsAvailable: false, - }, - }); - }; - - const setupData = async () => { - list = new List(listObj); - boardsStore.create(); - boardsStore.detail.issue = {}; - const label1 = new ListLabel({ - id: 3, - title: 'testing 123', - color: '#000cff', - text_color: 'white', - description: 'test', - }); - await waitForPromises(); - - list.issues[0].labels.push(label1); - }; - - beforeEach(() => { - mock = new MockAdapter(axios); - mock.onAny().reply(boardsMockInterceptor); - setMockEndpoints(); - return setupData(); - }); - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - list = null; - mock.restore(); - }); - - it('when details issue is empty does not show the element', () => { - mountComponent(); - expect(wrapper.find('[data-testid="board_card"').classes()).not.toContain('is-active'); - }); - - it('when detailIssue is equal to card issue shows the element', () => { - [boardsStore.detail.issue] = list.issues; - mountComponent(); - - expect(wrapper.classes()).toContain('is-active'); - }); - - it('when multiSelect does not contain issue removes multi select class', () => { - mountComponent(); - expect(wrapper.classes()).not.toContain('multi-select'); - }); - - it('when multiSelect contain issue add multi select class', () => { - boardsStore.multiSelect.list = [list.issues[0]]; - mountComponent(); - - expect(wrapper.classes()).toContain('multi-select'); - }); - - it('adds user-can-drag class if not disabled', () => { - mountComponent(); - expect(wrapper.classes()).toContain('user-can-drag'); - }); - - it('does not add user-can-drag class disabled', () => { - mountComponent({ disabled: true }); - - expect(wrapper.classes()).not.toContain('user-can-drag'); - }); - - it('does not add disabled class', () => { - mountComponent(); - expect(wrapper.classes()).not.toContain('is-disabled'); - }); - - it('adds disabled class is disabled is true', () => { - mountComponent({ disabled: true }); - - expect(wrapper.classes()).toContain('is-disabled'); - }); - - describe('mouse events', () => { - it('does not set detail issue if showDetail is false', () => { - mountComponent(); - expect(boardsStore.detail.issue).toEqual({}); - }); - - it('does not set detail issue if link is clicked', () => { - mountComponent(); - findIssueCardInner().find('a').trigger('mouseup'); - - expect(boardsStore.detail.issue).toEqual({}); - }); - - it('does not set detail issue if img is clicked', () => { - mountComponent({ - issue: { - ...list.issues[0], - assignees: [ - new ListAssignee({ - id: 1, - name: 'testing 123', - username: 'test', - avatar: 'test_image', - }), - ], - }, - }); - - findUserAvatarLink().trigger('mouseup'); - - expect(boardsStore.detail.issue).toEqual({}); - }); - - it('does not set detail issue if showDetail is false after mouseup', () => { - mountComponent(); - wrapper.trigger('mouseup'); - - expect(boardsStore.detail.issue).toEqual({}); - }); - }); - - describe('sidebarHub events', () => { - it('it does not closes all sidebars before showing an issue if an issue is opened', () => { - jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {}); - const [issue] = list.issues; - boardsStore.detail.issue = issue; - mountComponent(); - - wrapper.trigger('mousedown'); - - expect(sidebarEventHub.$emit).not.toHaveBeenCalledWith('sidebar.closeAll'); - }); - }); -}); diff --git a/spec/frontend/boards/components/board_card_layout_deprecated_spec.js b/spec/frontend/boards/components/board_card_layout_deprecated_spec.js deleted file mode 100644 index 5a81f3ecc26..00000000000 --- a/spec/frontend/boards/components/board_card_layout_deprecated_spec.js +++ /dev/null @@ -1,154 +0,0 @@ -/* global List */ -/* global ListLabel */ - -import { createLocalVue, shallowMount } from '@vue/test-utils'; - -import MockAdapter from 'axios-mock-adapter'; -import Vuex from 'vuex'; -import waitForPromises from 'helpers/wait_for_promises'; - -import '~/boards/models/label'; -import '~/boards/models/assignee'; -import '~/boards/models/list'; -import BoardCardLayout from '~/boards/components/board_card_layout_deprecated.vue'; -import issueCardInner from '~/boards/components/issue_card_inner_deprecated.vue'; -import { ISSUABLE } from '~/boards/constants'; -import boardsVuexStore from '~/boards/stores'; -import boardsStore from '~/boards/stores/boards_store'; -import axios from '~/lib/utils/axios_utils'; -import { listObj, boardsMockInterceptor, setMockEndpoints } from '../mock_data'; - -describe('Board card layout', () => { - let wrapper; - let mock; - let list; - let store; - - const localVue = createLocalVue(); - localVue.use(Vuex); - - const createStore = ({ getters = {}, actions = {} } = {}) => { - store = new Vuex.Store({ - ...boardsVuexStore, - actions, - getters, - }); - }; - - // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized - const mountComponent = ({ propsData = {}, provide = {} } = {}) => { - wrapper = shallowMount(BoardCardLayout, { - localVue, - stubs: { - issueCardInner, - }, - store, - propsData: { - list, - issue: list.issues[0], - disabled: false, - index: 0, - ...propsData, - }, - provide: { - groupId: null, - rootPath: '/', - scopedLabelsAvailable: false, - ...provide, - }, - }); - }; - - const setupData = () => { - list = new List(listObj); - boardsStore.create(); - boardsStore.detail.issue = {}; - const label1 = new ListLabel({ - id: 3, - title: 'testing 123', - color: '#000cff', - text_color: 'white', - description: 'test', - }); - return waitForPromises().then(() => { - list.issues[0].labels.push(label1); - }); - }; - - beforeEach(() => { - mock = new MockAdapter(axios); - mock.onAny().reply(boardsMockInterceptor); - setMockEndpoints(); - return setupData(); - }); - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - list = null; - mock.restore(); - }); - - describe('mouse events', () => { - it('sets showDetail to true on mousedown', async () => { - createStore(); - mountComponent(); - - wrapper.trigger('mousedown'); - await wrapper.vm.$nextTick(); - - expect(wrapper.vm.showDetail).toBe(true); - }); - - it('sets showDetail to false on mousemove', async () => { - createStore(); - mountComponent(); - wrapper.trigger('mousedown'); - await wrapper.vm.$nextTick(); - expect(wrapper.vm.showDetail).toBe(true); - wrapper.trigger('mousemove'); - await wrapper.vm.$nextTick(); - expect(wrapper.vm.showDetail).toBe(false); - }); - - it("calls 'setActiveId'", async () => { - const setActiveId = jest.fn(); - createStore({ - actions: { - setActiveId, - }, - }); - mountComponent(); - - wrapper.trigger('mouseup'); - await wrapper.vm.$nextTick(); - - expect(setActiveId).toHaveBeenCalledTimes(1); - expect(setActiveId).toHaveBeenCalledWith(expect.any(Object), { - id: list.issues[0].id, - sidebarType: ISSUABLE, - }); - }); - - it("calls 'setActiveId' when epic swimlanes is active", async () => { - const setActiveId = jest.fn(); - const isSwimlanesOn = () => true; - createStore({ - getters: { isSwimlanesOn }, - actions: { - setActiveId, - }, - }); - mountComponent(); - - wrapper.trigger('mouseup'); - await wrapper.vm.$nextTick(); - - expect(setActiveId).toHaveBeenCalledTimes(1); - expect(setActiveId).toHaveBeenCalledWith(expect.any(Object), { - id: list.issues[0].id, - sidebarType: ISSUABLE, - }); - }); - }); -}); diff --git a/spec/frontend/boards/components/board_column_deprecated_spec.js b/spec/frontend/boards/components/board_column_deprecated_spec.js deleted file mode 100644 index e6d65e48c3f..00000000000 --- a/spec/frontend/boards/components/board_column_deprecated_spec.js +++ /dev/null @@ -1,106 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import AxiosMockAdapter from 'axios-mock-adapter'; -import Vue, { nextTick } from 'vue'; - -import { TEST_HOST } from 'helpers/test_constants'; -import { listObj } from 'jest/boards/mock_data'; -import Board from '~/boards/components/board_column_deprecated.vue'; -import { ListType } from '~/boards/constants'; -import List from '~/boards/models/list'; -import axios from '~/lib/utils/axios_utils'; - -describe('Board Column Component', () => { - let wrapper; - let axiosMock; - - beforeEach(() => { - window.gon = {}; - axiosMock = new AxiosMockAdapter(axios); - axiosMock.onGet(`${TEST_HOST}/lists/1/issues`).reply(200, { issues: [] }); - }); - - afterEach(() => { - axiosMock.restore(); - - wrapper.destroy(); - - localStorage.clear(); - }); - - const createComponent = ({ - listType = ListType.backlog, - collapsed = false, - highlighted = false, - withLocalStorage = true, - } = {}) => { - const boardId = '1'; - - const listMock = { - ...listObj, - list_type: listType, - highlighted, - collapsed, - }; - - if (listType === ListType.assignee) { - delete listMock.label; - listMock.user = {}; - } - - // Making List reactive - const list = Vue.observable(new List(listMock)); - - if (withLocalStorage) { - localStorage.setItem( - `boards.${boardId}.${list.type}.${list.id}.expanded`, - (!collapsed).toString(), - ); - } - - wrapper = shallowMount(Board, { - propsData: { - boardId, - disabled: false, - list, - }, - provide: { - boardId, - }, - }); - }; - - const isExpandable = () => wrapper.classes('is-expandable'); - const isCollapsed = () => wrapper.classes('is-collapsed'); - - describe('Given different list types', () => { - it('is expandable when List Type is `backlog`', () => { - createComponent({ listType: ListType.backlog }); - - expect(isExpandable()).toBe(true); - }); - }); - - describe('expanded / collapsed column', () => { - it('has class is-collapsed when list is collapsed', () => { - createComponent({ collapsed: false }); - - expect(wrapper.vm.list.isExpanded).toBe(true); - }); - - it('does not have class is-collapsed when list is expanded', () => { - createComponent({ collapsed: true }); - - expect(isCollapsed()).toBe(true); - }); - }); - - describe('highlighting', () => { - it('scrolls to column when highlighted', async () => { - createComponent({ highlighted: true }); - - await nextTick(); - - expect(wrapper.element.scrollIntoView).toHaveBeenCalled(); - }); - }); -}); diff --git a/spec/frontend/boards/components/board_list_header_deprecated_spec.js b/spec/frontend/boards/components/board_list_header_deprecated_spec.js deleted file mode 100644 index db79e67fe78..00000000000 --- a/spec/frontend/boards/components/board_list_header_deprecated_spec.js +++ /dev/null @@ -1,174 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import AxiosMockAdapter from 'axios-mock-adapter'; -import Vue from 'vue'; - -import { TEST_HOST } from 'helpers/test_constants'; -import { listObj } from 'jest/boards/mock_data'; -import BoardListHeader from '~/boards/components/board_list_header_deprecated.vue'; -import { ListType } from '~/boards/constants'; -import List from '~/boards/models/list'; -import axios from '~/lib/utils/axios_utils'; - -describe('Board List Header Component', () => { - let wrapper; - let axiosMock; - - beforeEach(() => { - window.gon = {}; - axiosMock = new AxiosMockAdapter(axios); - axiosMock.onGet(`${TEST_HOST}/lists/1/issues`).reply(200, { issues: [] }); - }); - - afterEach(() => { - axiosMock.restore(); - - wrapper.destroy(); - - localStorage.clear(); - }); - - const createComponent = ({ - listType = ListType.backlog, - collapsed = false, - withLocalStorage = true, - currentUserId = 1, - } = {}) => { - const boardId = '1'; - - const listMock = { - ...listObj, - list_type: listType, - collapsed, - }; - - if (listType === ListType.assignee) { - delete listMock.label; - listMock.user = {}; - } - - // Making List reactive - const list = Vue.observable(new List(listMock)); - - if (withLocalStorage) { - localStorage.setItem( - `boards.${boardId}.${list.type}.${list.id}.expanded`, - (!collapsed).toString(), - ); - } - - wrapper = shallowMount(BoardListHeader, { - propsData: { - disabled: false, - list, - }, - provide: { - boardId, - currentUserId, - }, - }); - }; - - const isCollapsed = () => !wrapper.props().list.isExpanded; - const isExpanded = () => wrapper.vm.list.isExpanded; - - const findAddIssueButton = () => wrapper.find({ ref: 'newIssueBtn' }); - const findCaret = () => wrapper.find('.board-title-caret'); - - describe('Add issue button', () => { - const hasNoAddButton = [ListType.closed]; - const hasAddButton = [ - ListType.backlog, - ListType.label, - ListType.milestone, - ListType.iteration, - ListType.assignee, - ]; - - it.each(hasNoAddButton)('does not render when List Type is `%s`', (listType) => { - createComponent({ listType }); - - expect(findAddIssueButton().exists()).toBe(false); - }); - - it.each(hasAddButton)('does render when List Type is `%s`', (listType) => { - createComponent({ listType }); - - expect(findAddIssueButton().exists()).toBe(true); - }); - - it('has a test for each list type', () => { - Object.values(ListType).forEach((value) => { - expect([...hasAddButton, ...hasNoAddButton]).toContain(value); - }); - }); - - it('does not render when logged out', () => { - createComponent({ - currentUserId: null, - }); - - expect(findAddIssueButton().exists()).toBe(false); - }); - }); - - describe('expanding / collapsing the column', () => { - it('does not collapse when clicking the header', () => { - createComponent(); - - expect(isCollapsed()).toBe(false); - wrapper.find('[data-testid="board-list-header"]').trigger('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(isCollapsed()).toBe(false); - }); - }); - - it('collapses expanded Column when clicking the collapse icon', () => { - createComponent(); - - expect(isExpanded()).toBe(true); - findCaret().vm.$emit('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(isCollapsed()).toBe(true); - }); - }); - - it('expands collapsed Column when clicking the expand icon', () => { - createComponent({ collapsed: true }); - - expect(isCollapsed()).toBe(true); - findCaret().vm.$emit('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(isCollapsed()).toBe(false); - }); - }); - - it("when logged in it calls list update and doesn't set localStorage", () => { - jest.spyOn(List.prototype, 'update'); - - createComponent({ withLocalStorage: false }); - - findCaret().vm.$emit('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.list.update).toHaveBeenCalledTimes(1); - expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.expanded`)).toBe(null); - }); - }); - - it("when logged out it doesn't call list update and sets localStorage", () => { - jest.spyOn(List.prototype, 'update'); - - createComponent({ currentUserId: null }); - - findCaret().vm.$emit('click'); - - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.list.update).not.toHaveBeenCalled(); - expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.expanded`)).toBe(String(isExpanded())); - }); - }); - }); -}); diff --git a/spec/frontend/boards/components/boards_selector_deprecated_spec.js b/spec/frontend/boards/components/boards_selector_deprecated_spec.js deleted file mode 100644 index cc078861d75..00000000000 --- a/spec/frontend/boards/components/boards_selector_deprecated_spec.js +++ /dev/null @@ -1,214 +0,0 @@ -import { GlDropdown, GlLoadingIcon, GlDropdownSectionHeader } from '@gitlab/ui'; -import { mount } from '@vue/test-utils'; -import { nextTick } from 'vue'; -import { TEST_HOST } from 'spec/test_constants'; -import BoardsSelector from '~/boards/components/boards_selector_deprecated.vue'; -import boardsStore from '~/boards/stores/boards_store'; - -const throttleDuration = 1; - -function boardGenerator(n) { - return new Array(n).fill().map((board, index) => { - const id = `${index}`; - const name = `board${id}`; - - return { - id, - name, - }; - }); -} - -describe('BoardsSelector', () => { - let wrapper; - let allBoardsResponse; - let recentBoardsResponse; - const boards = boardGenerator(20); - const recentBoards = boardGenerator(5); - - const fillSearchBox = (filterTerm) => { - const searchBox = wrapper.find({ ref: 'searchBox' }); - const searchBoxInput = searchBox.find('input'); - searchBoxInput.setValue(filterTerm); - searchBoxInput.trigger('input'); - }; - - const getDropdownItems = () => wrapper.findAll('.js-dropdown-item'); - const getDropdownHeaders = () => wrapper.findAll(GlDropdownSectionHeader); - const getLoadingIcon = () => wrapper.find(GlLoadingIcon); - const findDropdown = () => wrapper.find(GlDropdown); - - beforeEach(() => { - const $apollo = { - queries: { - boards: { - loading: false, - }, - }, - }; - - boardsStore.setEndpoints({ - boardsEndpoint: '', - recentBoardsEndpoint: '', - listsEndpoint: '', - bulkUpdatePath: '', - boardId: '', - }); - - allBoardsResponse = Promise.resolve({ - data: { - group: { - boards: { - edges: boards.map((board) => ({ node: board })), - }, - }, - }, - }); - recentBoardsResponse = Promise.resolve({ - data: recentBoards, - }); - - boardsStore.allBoards = jest.fn(() => allBoardsResponse); - boardsStore.recentBoards = jest.fn(() => recentBoardsResponse); - - wrapper = mount(BoardsSelector, { - propsData: { - throttleDuration, - currentBoard: { - id: 1, - name: 'Development', - milestone_id: null, - weight: null, - assignee_id: null, - labels: [], - }, - boardBaseUrl: `${TEST_HOST}/board/base/url`, - hasMissingBoards: false, - canAdminBoard: true, - multipleIssueBoardsAvailable: true, - labelsPath: `${TEST_HOST}/labels/path`, - labelsWebUrl: `${TEST_HOST}/labels`, - projectId: 42, - groupId: 19, - scopedIssueBoardFeatureEnabled: true, - weights: [], - }, - mocks: { $apollo }, - attachTo: document.body, - }); - - wrapper.vm.$apollo.addSmartQuery = jest.fn((_, options) => { - wrapper.setData({ - [options.loadingKey]: true, - }); - }); - - // Emits gl-dropdown show event to simulate the dropdown is opened at initialization time - findDropdown().vm.$emit('show'); - }); - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - describe('loading', () => { - // we are testing loading state, so don't resolve responses until after the tests - afterEach(() => { - return Promise.all([allBoardsResponse, recentBoardsResponse]).then(() => nextTick()); - }); - - it('shows loading spinner', () => { - expect(getDropdownHeaders()).toHaveLength(0); - expect(getDropdownItems()).toHaveLength(0); - expect(getLoadingIcon().exists()).toBe(true); - }); - }); - - describe('loaded', () => { - beforeEach(async () => { - await wrapper.setData({ - loadingBoards: false, - }); - return Promise.all([allBoardsResponse, recentBoardsResponse]).then(() => nextTick()); - }); - - it('hides loading spinner', () => { - expect(getLoadingIcon().exists()).toBe(false); - }); - - describe('filtering', () => { - beforeEach(() => { - wrapper.setData({ - boards, - }); - - return nextTick(); - }); - - it('shows all boards without filtering', () => { - expect(getDropdownItems()).toHaveLength(boards.length + recentBoards.length); - }); - - it('shows only matching boards when filtering', () => { - const filterTerm = 'board1'; - const expectedCount = boards.filter((board) => board.name.includes(filterTerm)).length; - - fillSearchBox(filterTerm); - - return nextTick().then(() => { - expect(getDropdownItems()).toHaveLength(expectedCount); - }); - }); - - it('shows message if there are no matching boards', () => { - fillSearchBox('does not exist'); - - return nextTick().then(() => { - expect(getDropdownItems()).toHaveLength(0); - expect(wrapper.text().includes('No matching boards found')).toBe(true); - }); - }); - }); - - describe('recent boards section', () => { - it('shows only when boards are greater than 10', () => { - wrapper.setData({ - boards, - }); - - return nextTick().then(() => { - expect(getDropdownHeaders()).toHaveLength(2); - }); - }); - - it('does not show when boards are less than 10', () => { - wrapper.setData({ - boards: boards.slice(0, 5), - }); - - return nextTick().then(() => { - expect(getDropdownHeaders()).toHaveLength(0); - }); - }); - - it('does not show when recentBoards api returns empty array', () => { - wrapper.setData({ - recentBoards: [], - }); - - return nextTick().then(() => { - expect(getDropdownHeaders()).toHaveLength(0); - }); - }); - - it('does not show when search is active', () => { - fillSearchBox('Random string'); - - return nextTick().then(() => { - expect(getDropdownHeaders()).toHaveLength(0); - }); - }); - }); - }); -}); diff --git a/spec/frontend/boards/components/issue_time_estimate_deprecated_spec.js b/spec/frontend/boards/components/issue_time_estimate_deprecated_spec.js deleted file mode 100644 index fafebaf3a4e..00000000000 --- a/spec/frontend/boards/components/issue_time_estimate_deprecated_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -import { shallowMount } from '@vue/test-utils'; -import IssueTimeEstimate from '~/boards/components/issue_time_estimate_deprecated.vue'; -import boardsStore from '~/boards/stores/boards_store'; - -describe('Issue Time Estimate component', () => { - let wrapper; - - beforeEach(() => { - boardsStore.create(); - }); - - afterEach(() => { - wrapper.destroy(); - }); - - describe('when limitToHours is false', () => { - beforeEach(() => { - boardsStore.timeTracking.limitToHours = false; - wrapper = shallowMount(IssueTimeEstimate, { - propsData: { - estimate: 374460, - }, - }); - }); - - it('renders the correct time estimate', () => { - expect(wrapper.find('time').text().trim()).toEqual('2w 3d 1m'); - }); - - it('renders expanded time estimate in tooltip', () => { - expect(wrapper.find('.js-issue-time-estimate').text()).toContain('2 weeks 3 days 1 minute'); - }); - - it('prevents tooltip xss', (done) => { - const alertSpy = jest.spyOn(window, 'alert'); - wrapper.setProps({ estimate: 'Foo <script>alert("XSS")</script>' }); - wrapper.vm.$nextTick(() => { - expect(alertSpy).not.toHaveBeenCalled(); - expect(wrapper.find('time').text().trim()).toEqual('0m'); - expect(wrapper.find('.js-issue-time-estimate').text()).toContain('0m'); - done(); - }); - }); - }); - - describe('when limitToHours is true', () => { - beforeEach(() => { - boardsStore.timeTracking.limitToHours = true; - wrapper = shallowMount(IssueTimeEstimate, { - propsData: { - estimate: 374460, - }, - }); - }); - - it('renders the correct time estimate', () => { - expect(wrapper.find('time').text().trim()).toEqual('104h 1m'); - }); - - it('renders expanded time estimate in tooltip', () => { - expect(wrapper.find('.js-issue-time-estimate').text()).toContain('104 hours 1 minute'); - }); - }); -}); |