mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 01:32:18 +02:00
Explore Test Automation (#320)
* config jest and add setup for unittest * config jest coverage * example of unit testing a Status widget/component * add license for test file * add test/run command in the .travis.yml * add mock store and i18n for vue jest * add mock file missing * add mock router * add lincence to mock file & decodeHtml to setup file * add mock axios instance & fix eslint on tests folder * add test components > views > ActionButton component * fix for test coverage success * refactor test file * add test Views > Autogenview.vue (Navigation Guard, Watchers, Computed) * history mode mockRouter, refactor test code, test Autogenview > fetchData (routeName) * test Views > AutogenView.vue (processing 31%) * add mock router exception & test Views > AutogenView.vue (processing 43%) * test Views > AutogenView (processing 65%), add test onSearch, closeAction, execAction, listUuidOpts * refactor and add comment test files * test Views > AutogenView (processing 91%) * add comment file AutogenView.spec.js * test Views > AutogenView.vue (handleSubmit method) Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
64d95fb6e3
commit
338de72665
7
ui/.babelrc
Normal file
7
ui/.babelrc
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": ["require-context-hook"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,3 +22,4 @@ cache:
|
||||
npm: false
|
||||
script:
|
||||
- npm run lint && npm run build
|
||||
- npm run test:unit
|
||||
|
||||
@ -15,10 +15,11 @@
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
module.exports = {
|
||||
const babelConfig = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
],
|
||||
plugins: []
|
||||
// if your use import on Demand, Use this code
|
||||
// ,
|
||||
// plugins: [
|
||||
@ -29,3 +30,9 @@ module.exports = {
|
||||
// } ]
|
||||
// ]
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
babelConfig.plugins.push('require-context-hook')
|
||||
}
|
||||
|
||||
module.exports = babelConfig
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
// under the License.
|
||||
|
||||
module.exports = {
|
||||
testURL: 'http://localhost/',
|
||||
setupFiles: ['<rootDir>/tests/setup.js'],
|
||||
moduleFileExtensions: [
|
||||
'js',
|
||||
'jsx',
|
||||
@ -24,11 +26,13 @@ module.exports = {
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.vue$': 'vue-jest',
|
||||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
|
||||
'.+\\.(css|styl|less|sass|scss|png|svg|jpg|ttf|woff|woff2)?$': 'jest-transform-stub',
|
||||
'^.+\\.jsx?$': 'babel-jest'
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^@/(.*)$': '<rootDir>/src/$1'
|
||||
'.+\\.svg?.+$': 'jest-transform-stub',
|
||||
'^@/(.*)$': '<rootDir>/src/$1',
|
||||
'^@public/(.*)$': '<rootDir>/public/$1'
|
||||
},
|
||||
snapshotSerializers: [
|
||||
'jest-serializer-vue'
|
||||
@ -36,5 +40,14 @@ module.exports = {
|
||||
testMatch: [
|
||||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
|
||||
],
|
||||
testURL: 'http://localhost/'
|
||||
transformIgnorePatterns: [
|
||||
'<rootDir>/node_modules/(?!ant-design-vue|vue)'
|
||||
],
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: [
|
||||
'<rootDir>/src/**/*.{js,vue}',
|
||||
'!**/node_modules/**',
|
||||
'!<rootDir>/src/locales/*.{js, json}'
|
||||
],
|
||||
coverageReporters: ['html', 'text-summary']
|
||||
}
|
||||
|
||||
63
ui/package-lock.json
generated
63
ui/package-lock.json
generated
@ -3803,6 +3803,7 @@
|
||||
"vue-loader": "^15.9.2",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"webpack": "^4.0.0",
|
||||
"webpack-bundle-analyzer": "^3.8.0",
|
||||
"webpack-chain": "^6.4.0",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
@ -10190,9 +10191,9 @@
|
||||
}
|
||||
},
|
||||
"duplexer": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
|
||||
"integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
|
||||
"dev": true
|
||||
},
|
||||
"duplexer3": {
|
||||
@ -18055,9 +18056,9 @@
|
||||
}
|
||||
},
|
||||
"opener": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz",
|
||||
"integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
|
||||
"integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
|
||||
"dev": true
|
||||
},
|
||||
"opn": {
|
||||
@ -24873,6 +24874,56 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-bundle-analyzer": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz",
|
||||
"integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.1.1",
|
||||
"acorn-walk": "^7.1.1",
|
||||
"bfj": "^6.1.1",
|
||||
"chalk": "^2.4.1",
|
||||
"commander": "^2.18.0",
|
||||
"ejs": "^2.6.1",
|
||||
"express": "^4.16.3",
|
||||
"filesize": "^3.6.1",
|
||||
"gzip-size": "^5.0.0",
|
||||
"lodash": "^4.17.19",
|
||||
"mkdirp": "^0.5.1",
|
||||
"opener": "^1.5.1",
|
||||
"ws": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-walk": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
|
||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
||||
"dev": true
|
||||
},
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-chain": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack-chain/-/webpack-chain-6.5.1.tgz",
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
"ant-design-vue": "~1.6.2",
|
||||
"antd-theme-webpack-plugin": "^1.3.4",
|
||||
"axios": "^0.19.2",
|
||||
"babel-plugin-require-context-hook": "^1.0.0",
|
||||
"core-js": "^3.6.5",
|
||||
"enquire.js": "^2.1.6",
|
||||
"js-cookie": "^2.2.1",
|
||||
@ -153,6 +154,9 @@
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
|
||||
@ -80,7 +80,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
actionBadge: []
|
||||
actionBadge: {}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
@ -132,7 +132,7 @@ export default {
|
||||
this.$emit('exec-action', action)
|
||||
},
|
||||
handleShowBadge () {
|
||||
const dataBadge = {}
|
||||
this.actionBadge = {}
|
||||
const arrAsync = []
|
||||
const actionBadge = this.actions.filter(action => action.showBadge === true)
|
||||
|
||||
@ -157,7 +157,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
if (json[responseJsonName].count && json[responseJsonName].count > 0) {
|
||||
if (json[responseJsonName] && json[responseJsonName].count && json[responseJsonName].count > 0) {
|
||||
response.count = json[responseJsonName].count
|
||||
}
|
||||
|
||||
@ -170,12 +170,10 @@ export default {
|
||||
|
||||
Promise.all(arrAsync).then(response => {
|
||||
for (let j = 0; j < response.length; j++) {
|
||||
this.$set(dataBadge, response[j].api, {})
|
||||
this.$set(dataBadge[response[j].api], 'badgeNum', response[j].count)
|
||||
this.$set(this.actionBadge, response[j].api, {})
|
||||
this.$set(this.actionBadge[response[j].api], 'badgeNum', response[j].count)
|
||||
}
|
||||
})
|
||||
|
||||
this.actionBadge = dataBadge
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,19 +164,19 @@ export default {
|
||||
jobId: jobid,
|
||||
successMessage: `${this.$t('message.success.migrating')} ${this.resource.name}`,
|
||||
successMethod: () => {
|
||||
this.$parent.$parent.close()
|
||||
this.$emit('close-action')
|
||||
},
|
||||
errorMessage: this.$t('message.migrating.failed'),
|
||||
errorMethod: () => {
|
||||
this.$parent.$parent.close()
|
||||
this.$emit('close-action')
|
||||
},
|
||||
loadingMessage: `${this.$t('message.migrating.processing')} ${this.resource.name}`,
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.$parent.$parent.close()
|
||||
this.$emit('close-action')
|
||||
}
|
||||
})
|
||||
this.$parent.$parent.close()
|
||||
this.$emit('close-action')
|
||||
}).catch(error => {
|
||||
this.$notification.error({
|
||||
message: this.$t('message.request.failed'),
|
||||
|
||||
88
ui/tests/common/index.js
Normal file
88
ui/tests/common/index.js
Normal file
@ -0,0 +1,88 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 mockI18n from '../mock/mockI18n'
|
||||
import mockStore from '../mock/mockStore'
|
||||
import mockRouter from '../mock/mockRouter'
|
||||
|
||||
import localVue from '../setup'
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { pollJobPlugin, notifierPlugin } from '@/utils/plugins'
|
||||
|
||||
localVue.use(pollJobPlugin)
|
||||
localVue.use(notifierPlugin)
|
||||
|
||||
function createMockRouter (newRoutes = []) {
|
||||
let routes = []
|
||||
if (!newRoutes || Object.keys(newRoutes).length === 0) {
|
||||
return mockRouter.mock(routes)
|
||||
}
|
||||
|
||||
routes = [...newRoutes]
|
||||
|
||||
return mockRouter.mock(routes)
|
||||
}
|
||||
|
||||
function createMockI18n (locale = 'en', messages = {}) {
|
||||
return mockI18n.mock(locale, messages)
|
||||
}
|
||||
|
||||
function createMockStore (state = {}, actions = {}) {
|
||||
return mockStore.mock(state, actions)
|
||||
}
|
||||
|
||||
function decodeHtml (html) {
|
||||
const text = document.createElement('textarea')
|
||||
text.innerHTML = html
|
||||
|
||||
return text.value
|
||||
}
|
||||
|
||||
function createFactory (component, options) {
|
||||
var {
|
||||
router = null,
|
||||
i18n = null,
|
||||
store = null,
|
||||
props = {},
|
||||
data = {},
|
||||
mocks = {}
|
||||
} = options
|
||||
|
||||
if (!router) router = createMockRouter()
|
||||
if (!i18n) i18n = createMockI18n()
|
||||
if (!store) store = createMockStore()
|
||||
|
||||
return mount(component, {
|
||||
localVue,
|
||||
router,
|
||||
i18n,
|
||||
store,
|
||||
propsData: props,
|
||||
mocks,
|
||||
data () {
|
||||
return { ...data }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
createFactory,
|
||||
createMockRouter,
|
||||
createMockI18n,
|
||||
createMockStore,
|
||||
decodeHtml
|
||||
}
|
||||
22
ui/tests/mock/mockAxios.js
Normal file
22
ui/tests/mock/mockAxios.js
Normal file
@ -0,0 +1,22 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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.
|
||||
|
||||
const mockAxios = jest.genMockFromModule('axios')
|
||||
|
||||
mockAxios.create = jest.fn(() => mockAxios)
|
||||
|
||||
export default mockAxios
|
||||
29
ui/tests/mock/mockI18n.js
Normal file
29
ui/tests/mock/mockI18n.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 VueI18n from 'vue-i18n'
|
||||
|
||||
const mockI18n = {
|
||||
mock: (locale = 'en', message = {}) => {
|
||||
return new VueI18n({
|
||||
locale: locale,
|
||||
messages: message
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default mockI18n
|
||||
64
ui/tests/mock/mockRouter.js
Normal file
64
ui/tests/mock/mockRouter.js
Normal file
@ -0,0 +1,64 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 VueRouter from 'vue-router'
|
||||
|
||||
const mockRouter = {
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
meta: { icon: 'home' },
|
||||
children: []
|
||||
}
|
||||
],
|
||||
mock: (routes = []) => {
|
||||
mockRouter.routes[0].children = [
|
||||
{
|
||||
path: '/exception',
|
||||
name: 'exception',
|
||||
children: [
|
||||
{
|
||||
path: '/exception/403',
|
||||
name: 403,
|
||||
hidden: true,
|
||||
meta: { icon: 'icon-error-test' }
|
||||
},
|
||||
{
|
||||
path: '/exception/404',
|
||||
name: 404,
|
||||
hidden: true,
|
||||
meta: { icon: 'icon-error-test' }
|
||||
},
|
||||
{
|
||||
path: '/exception/500',
|
||||
name: 500,
|
||||
hidden: true,
|
||||
meta: { icon: 'icon-error-test' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
if (routes && routes.length > 0) {
|
||||
mockRouter.routes[0].children = [...mockRouter.routes[0].children, ...routes]
|
||||
}
|
||||
|
||||
return new VueRouter({ routes: mockRouter.routes, mode: 'history' })
|
||||
}
|
||||
}
|
||||
|
||||
export default mockRouter
|
||||
50
ui/tests/mock/mockStore.js
Normal file
50
ui/tests/mock/mockStore.js
Normal file
@ -0,0 +1,50 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 Vuex from 'vuex'
|
||||
|
||||
const mockStore = {
|
||||
state: {},
|
||||
mock: (state, actions) => {
|
||||
mockStore.state = {
|
||||
app: {
|
||||
device: 'desktop'
|
||||
},
|
||||
user: {},
|
||||
permission: {}
|
||||
}
|
||||
|
||||
if (state && Object.keys(state).length > 0) {
|
||||
mockStore.state = { ...mockStore.state, ...state }
|
||||
}
|
||||
|
||||
if (!actions) {
|
||||
actions = {}
|
||||
}
|
||||
|
||||
return new Vuex.Store({
|
||||
state: mockStore.state,
|
||||
getters: {
|
||||
apis: () => mockStore.state.user.apis,
|
||||
userInfo: () => mockStore.state.user.info
|
||||
},
|
||||
actions
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default mockStore
|
||||
30
ui/tests/mockData/ActionButton.mock.json
Normal file
30
ui/tests/mockData/ActionButton.mock.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"messages": {
|
||||
"en": { "label.action": "action-en" },
|
||||
"de": { "label.action": "action-de" }
|
||||
},
|
||||
"apis": {
|
||||
"test-api-case-1": {},
|
||||
"test-api-case-2": {},
|
||||
"test-api-case-3": {},
|
||||
"test-api-case-4": {},
|
||||
"test-api-case-5": {},
|
||||
"test-api-case-6": {}
|
||||
},
|
||||
"routes": [
|
||||
{
|
||||
"name": "testRouter1",
|
||||
"path": "/test-router-1",
|
||||
"meta": {
|
||||
"name": "systemvm"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "testRouter2",
|
||||
"path": "/test-router-2",
|
||||
"meta": {
|
||||
"name": "test-name"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
198
ui/tests/mockData/AutogenView.mock.json
Normal file
198
ui/tests/mockData/AutogenView.mock.json
Normal file
@ -0,0 +1,198 @@
|
||||
{
|
||||
"messages": {
|
||||
"en": {
|
||||
"labelname": "test-name-en",
|
||||
"displaytext": "description-en",
|
||||
"label.column1": "column1-en",
|
||||
"label.column2": "column2-en",
|
||||
"label.column3": "column3-en",
|
||||
"label.id": "uuid-en",
|
||||
"label.name": "name-en",
|
||||
"label.domainid": "domain-en",
|
||||
"label.self": "self-en",
|
||||
"label.all": "all-en",
|
||||
"label.tags": "tags-en",
|
||||
"label.account": "account-en",
|
||||
"label.domainids": "domainids-en",
|
||||
"label.keypair": "keypair-en",
|
||||
"label.filterby": "filterby-en",
|
||||
"label.refresh": "refresh-en",
|
||||
"message.error.required.input": "required-en",
|
||||
"message.error.select": "select-en",
|
||||
"label.search": "search-en",
|
||||
"label.quota.configuration": "quota-configuration-en",
|
||||
"label.quota.value": "quota-value-en",
|
||||
"label.quota.tariff.effectivedate": "quota-effectivedate-en",
|
||||
"label.confirmpassword": "confirmpassword-en",
|
||||
"label.confirmpassword.description": "confirmpassword-description-en",
|
||||
"label.open.documentation": "open",
|
||||
"label.metrics": "metrics",
|
||||
"label.showing": "Showing",
|
||||
"label.of": "of",
|
||||
"label.items": "items",
|
||||
"label.page": "page",
|
||||
"label.view.console": "view-console-en",
|
||||
"error.fetching.async.job.result": "Error encountered while fetching async job result",
|
||||
"label.cancel": "cancel",
|
||||
"label.ok": "ok"
|
||||
},
|
||||
"de": {
|
||||
"labelname": "test-name-de",
|
||||
"displaytext": "description-de",
|
||||
"label.column1": "column1-de",
|
||||
"label.column2": "column2-de",
|
||||
"label.column3": "column3-de",
|
||||
"label.id": "uuid-de",
|
||||
"label.name": "name-de",
|
||||
"label.domainid": "domain-de",
|
||||
"label.self": "self-de",
|
||||
"label.all": "all-de",
|
||||
"label.tags": "tags-de",
|
||||
"label.account": "account-de",
|
||||
"label.domainids": "domainids-de",
|
||||
"label.keypair": "keypair-de",
|
||||
"label.filterby": "filterby-de",
|
||||
"label.refresh": "refresh-de",
|
||||
"message.error.required.input": "required-de",
|
||||
"message.error.select": "select-de",
|
||||
"label.search": "search-de",
|
||||
"label.quota.configuration": "quota-configuration-de",
|
||||
"label.quota.value": "quota-value-de",
|
||||
"label.quota.tariff.effectivedate": "quota-effectivedate-de",
|
||||
"label.confirmpassword": "confirmpassword-de",
|
||||
"label.confirmpassword.description": "confirmpassword-description-de",
|
||||
"label.open.documentation": "open",
|
||||
"label.metrics": "metrics",
|
||||
"label.showing": "Showing",
|
||||
"label.of": "of",
|
||||
"label.items": "items",
|
||||
"label.page": "page",
|
||||
"label.view.console": "view-console-de",
|
||||
"error.fetching.async.job.result": "Error encountered while fetching async job result",
|
||||
"label.cancel": "cancel",
|
||||
"label.ok": "ok"
|
||||
}
|
||||
},
|
||||
"apis": {
|
||||
"testApiNameCase1": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"testApiNameCase2": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"testApiNameCase3": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"testApiNameCase4": {
|
||||
"params": {},
|
||||
"response": [
|
||||
{
|
||||
"name": "column2",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "column1",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "column3",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"testApiNameCase5": {
|
||||
"params": [
|
||||
{
|
||||
"name": "column2",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "column1",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "column3",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"response": []
|
||||
},
|
||||
"testApiNameCase6": {
|
||||
"params": [
|
||||
{
|
||||
"name": "id",
|
||||
"type": "uuid"
|
||||
},
|
||||
{
|
||||
"name": "tags",
|
||||
"type": "list"
|
||||
},
|
||||
{
|
||||
"name": "column1",
|
||||
"type": "list"
|
||||
},
|
||||
{
|
||||
"name": "column2",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "account",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "confirmpassword",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"response": []
|
||||
},
|
||||
"listTemplates": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"listIsos": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"listRoles": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"listHosts": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"listTestApiNames": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"createAccount": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"addAccountToProject": {
|
||||
"params": {},
|
||||
"response": []
|
||||
},
|
||||
"quotaEmailTemplateList": {
|
||||
"params": {},
|
||||
"response": []
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"roletype": "Normal",
|
||||
"account": "test-account",
|
||||
"domainid": "test-domain-id"
|
||||
}
|
||||
}
|
||||
24
ui/tests/mockData/MigrateWizard.mock.json
Normal file
24
ui/tests/mockData/MigrateWizard.mock.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"messages": {
|
||||
"en": {
|
||||
"name": "name-en",
|
||||
"Suitability": "Suitability-en",
|
||||
"cpuused": "cpuused-en",
|
||||
"memused": "memused-en",
|
||||
"select": "select-en",
|
||||
"ok": "ok-en",
|
||||
"message.load.host.failed": "Failed to load hosts",
|
||||
"message.migrating.vm.to.host.failed": "Failed to migrate VM to host"
|
||||
},
|
||||
"de": {
|
||||
"name": "name-de",
|
||||
"Suitability": "Suitability-de",
|
||||
"cpuused": "cpuused-de",
|
||||
"memused": "memused-de",
|
||||
"select": "select-de",
|
||||
"ok": "ok-de",
|
||||
"message.load.host.failed": "Failed to load hosts",
|
||||
"message.migrating.vm.to.host.failed": "Failed to migrate VM to host"
|
||||
}
|
||||
}
|
||||
}
|
||||
38
ui/tests/mockData/Status.mock.json
Normal file
38
ui/tests/mockData/Status.mock.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"messages": {
|
||||
"en": {
|
||||
"state.running": "Running",
|
||||
"state.migrating": "Migrating",
|
||||
"state.stopped": "Stopped",
|
||||
"state.starting": "Starting",
|
||||
"state.stopping": "Stopping",
|
||||
"state.suspended": "Suspended",
|
||||
"state.pending": "Pending",
|
||||
"state.expunging": "Expunging",
|
||||
"state.error": "Error",
|
||||
"message.publicip.state.allocated": "Allocated",
|
||||
"message.publicip.state.created": "Created",
|
||||
"message.vmsnapshot.state.active": "Active",
|
||||
"message.vm.state.active": "Active",
|
||||
"message.volume.state.active": "Active",
|
||||
"message.guestnetwork.state.active": "Active",
|
||||
"message.publicip.state.active": "Active",
|
||||
"Created": "Created",
|
||||
"Active": "Active",
|
||||
"Allocated": "Allocated",
|
||||
"Error": "Error",
|
||||
"Expunging": "Expunging",
|
||||
"Suspended": "Suspended",
|
||||
"Pending": "Pending",
|
||||
"Running": "Running",
|
||||
"Starting": "Starting",
|
||||
"Another": "Another",
|
||||
"Ready": "Ready",
|
||||
"Disabled": "Disabled",
|
||||
"Migrating": "Migrating",
|
||||
"Stopping": "Stopping",
|
||||
"Alert": "Alert",
|
||||
"Stopped": "Stopped"
|
||||
}
|
||||
}
|
||||
}
|
||||
49
ui/tests/setup.js
Normal file
49
ui/tests/setup.js
Normal file
@ -0,0 +1,49 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import Antd from 'ant-design-vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import VueI18n from 'vue-i18n'
|
||||
import VueStorage from 'vue-ls'
|
||||
import VueClipboard from 'vue-clipboard2'
|
||||
import config from '@/config/settings'
|
||||
import { createLocalVue } from '@vue/test-utils'
|
||||
import registerRequireContextHook from 'babel-plugin-require-context-hook/register'
|
||||
|
||||
const localVue = createLocalVue()
|
||||
|
||||
Vue.use(Antd)
|
||||
Vue.use(VueStorage, config.storageOptions)
|
||||
|
||||
localVue.use(VueRouter)
|
||||
localVue.use(VueI18n)
|
||||
localVue.use(Vuex)
|
||||
localVue.use(VueClipboard)
|
||||
|
||||
registerRequireContextHook()
|
||||
|
||||
window.matchMedia = window.matchMedia || function () {
|
||||
return {
|
||||
matches: false,
|
||||
addListener: function () {},
|
||||
removeListener: function () {}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = localVue
|
||||
337
ui/tests/unit/components/view/ActionButton.spec.js
Normal file
337
ui/tests/unit/components/view/ActionButton.spec.js
Normal file
@ -0,0 +1,337 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 mockAxios from '../../../mock/mockAxios'
|
||||
import ActionButton from '@/components/view/ActionButton'
|
||||
import common from '../../../common'
|
||||
import mockData from '../../../mockData/ActionButton.mock.json'
|
||||
|
||||
jest.mock('axios', () => mockAxios)
|
||||
|
||||
let router, store, i18n
|
||||
const state = {
|
||||
user: {
|
||||
apis: mockData.apis
|
||||
}
|
||||
}
|
||||
router = common.createMockRouter(mockData.routes)
|
||||
store = common.createMockStore(state)
|
||||
i18n = common.createMockI18n('en', mockData.messages)
|
||||
|
||||
const factory = (opts = {}) => {
|
||||
router = opts.router || router
|
||||
store = opts.store || store
|
||||
i18n = opts.i18n || i18n
|
||||
|
||||
return common.createFactory(ActionButton, {
|
||||
router,
|
||||
store,
|
||||
i18n,
|
||||
props: opts.props || {},
|
||||
data: opts.data || {}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Components > View > ActionButton.vue', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe('Template', () => {
|
||||
it('Button action is show', () => {
|
||||
const expected = '<i aria-label="icon: plus" class="anticon anticon-plus">'
|
||||
const wrapper = factory()
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
const received = wrapper.html()
|
||||
|
||||
expect(received).not.toContain(expected)
|
||||
})
|
||||
})
|
||||
|
||||
it('Normal button action is show', () => {
|
||||
const expected = '<i aria-label="icon: plus" class="anticon anticon-plus">'
|
||||
const propsData = {
|
||||
actions: [
|
||||
{
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-1',
|
||||
showBadge: false,
|
||||
icon: 'plus',
|
||||
dataView: false,
|
||||
listView: true
|
||||
}
|
||||
],
|
||||
dataView: false,
|
||||
listView: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
const received = wrapper.html()
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
})
|
||||
|
||||
it('Badge button action is show', (done) => {
|
||||
const expected = '<span class="button-action-badge ant-badge">'
|
||||
const propsData = {
|
||||
actions: [
|
||||
{
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-2',
|
||||
showBadge: true,
|
||||
icon: 'plus',
|
||||
dataView: true
|
||||
}
|
||||
],
|
||||
dataView: true
|
||||
}
|
||||
const dataMock = {
|
||||
testapinameresponse: {
|
||||
count: 0,
|
||||
testapiname: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockImplementation(() => Promise.resolve(dataMock))
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
const wrapperHtml = wrapper.html()
|
||||
const received = common.decodeHtml(wrapperHtml)
|
||||
|
||||
expect(received).toContain(expected)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Method', () => {
|
||||
describe('handleShowBadge()', () => {
|
||||
it('check the api is called and returned is not null', (done) => {
|
||||
const postData = new URLSearchParams()
|
||||
const expected = { 'test-api-case-3': { badgeNum: 2 } }
|
||||
const dataMock = { testapinameresponse: { count: 2 } }
|
||||
const propsData = {
|
||||
actions: [
|
||||
{
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-3',
|
||||
showBadge: true,
|
||||
icon: 'plus',
|
||||
dataView: true
|
||||
}
|
||||
],
|
||||
dataView: true
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(dataMock)
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mockAxios).toHaveBeenCalledTimes(1)
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
data: postData,
|
||||
method: 'GET',
|
||||
params: {
|
||||
command: 'test-api-case-3',
|
||||
response: 'json'
|
||||
},
|
||||
url: '/'
|
||||
})
|
||||
expect(wrapper.vm.actionBadge).toEqual(expected)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check the api is called returned is null', (done) => {
|
||||
const postData = new URLSearchParams()
|
||||
const expected = { 'test-api-case-4': { badgeNum: 0 } }
|
||||
const dataMock = { data: [] }
|
||||
const propsData = {
|
||||
actions: [
|
||||
{
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-4',
|
||||
showBadge: true,
|
||||
icon: 'plus',
|
||||
dataView: true
|
||||
}
|
||||
],
|
||||
dataView: true
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(dataMock)
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mockAxios).toHaveBeenCalledTimes(1)
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
data: postData,
|
||||
method: 'GET',
|
||||
params: {
|
||||
command: 'test-api-case-4',
|
||||
response: 'json'
|
||||
},
|
||||
url: '/'
|
||||
})
|
||||
expect(wrapper.vm.actionBadge).toEqual(expected)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check the api is called and throws error', (done) => {
|
||||
const postData = new URLSearchParams()
|
||||
const propsData = {
|
||||
actions: [
|
||||
{
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-5',
|
||||
showBadge: true,
|
||||
icon: 'plus',
|
||||
dataView: true
|
||||
}
|
||||
],
|
||||
dataView: true
|
||||
}
|
||||
const errorMessage = 'errMethodMessage'
|
||||
|
||||
mockAxios.mockImplementationOnce(() => Promise.reject(errorMessage))
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mockAxios).toHaveBeenCalledTimes(1)
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
data: postData,
|
||||
method: 'GET',
|
||||
params: {
|
||||
command: 'test-api-case-5',
|
||||
response: 'json'
|
||||
},
|
||||
url: '/'
|
||||
})
|
||||
expect(wrapper.vm.actionBadge).toEqual({})
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('execAction()', () => {
|
||||
it('check emitted events are executed', async () => {
|
||||
const expected = {
|
||||
icon: 'plus',
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-6',
|
||||
showBadge: false,
|
||||
dataView: true,
|
||||
resource: {
|
||||
id: 'test-resource-id'
|
||||
}
|
||||
}
|
||||
const propsData = {
|
||||
actions: [
|
||||
{
|
||||
icon: 'plus',
|
||||
label: 'label.action',
|
||||
api: 'test-api-case-6',
|
||||
showBadge: false,
|
||||
dataView: true
|
||||
}
|
||||
],
|
||||
dataView: true,
|
||||
resource: {
|
||||
id: 'test-resource-id'
|
||||
}
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
await wrapper.find('button').trigger('click')
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
expect(wrapper.emitted()['exec-action'][0]).toEqual([expected])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Watcher', () => {
|
||||
describe('handleShowBadge()', () => {
|
||||
it('check handleShowBadge() is not called with empty resource', async () => {
|
||||
const wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id'
|
||||
}
|
||||
}
|
||||
})
|
||||
const handleShowBadge = jest.spyOn(wrapper.vm, 'handleShowBadge')
|
||||
wrapper.setProps({
|
||||
resource: null
|
||||
})
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(handleShowBadge).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('check handleShowBadge() is not called with resource containing id null', async () => {
|
||||
const wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleShowBadge = jest.spyOn(wrapper.vm, 'handleShowBadge')
|
||||
wrapper.setProps({
|
||||
resource: { id: null }
|
||||
})
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(handleShowBadge).not.toBeCalled()
|
||||
})
|
||||
|
||||
it('check handleShowBadge() is not called with changed resource data', async () => {
|
||||
const wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id-1'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
wrapper.setProps({
|
||||
resource: {
|
||||
id: 'test-resource-id-2'
|
||||
}
|
||||
})
|
||||
const handleShowBadge = jest.spyOn(wrapper.vm, 'handleShowBadge')
|
||||
await wrapper.vm.$nextTick()
|
||||
expect(handleShowBadge).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
395
ui/tests/unit/components/widgets/Status.spec.js
Normal file
395
ui/tests/unit/components/widgets/Status.spec.js
Normal file
@ -0,0 +1,395 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 Status from '@/components/widgets/Status'
|
||||
import common from '../../../common'
|
||||
import mockData from '../../../mockData/Status.mock.json'
|
||||
|
||||
let router, i18n
|
||||
|
||||
router = common.createMockRouter()
|
||||
i18n = common.createMockI18n('en', mockData.messages)
|
||||
|
||||
const factory = (opts = {}) => {
|
||||
router = opts.router || router
|
||||
i18n = opts.i18n || i18n
|
||||
|
||||
return common.createFactory(Status, {
|
||||
router,
|
||||
i18n,
|
||||
props: opts.props || {},
|
||||
data: opts.data || {}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Components > Widgets > Status.vue', () => {
|
||||
describe('Methods', () => {
|
||||
describe('getText()', () => {
|
||||
it('getText() is called and the value returned is null', () => {
|
||||
const propsData = {
|
||||
text: 'Running',
|
||||
displayText: false
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text"></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Running', () => {
|
||||
const propsData = {
|
||||
text: 'Running',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Running</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Stopped', () => {
|
||||
const propsData = {
|
||||
text: 'Stopped',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Stopped</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Starting', () => {
|
||||
const propsData = {
|
||||
text: 'Starting',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Starting</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Stopping', () => {
|
||||
const propsData = {
|
||||
text: 'Stopping',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Stopping</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Suspended', () => {
|
||||
const propsData = {
|
||||
text: 'Suspended',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Suspended</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Pending', () => {
|
||||
const propsData = {
|
||||
text: 'Pending',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Pending</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Expunging', () => {
|
||||
const propsData = {
|
||||
text: 'Expunging',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Expunging</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getText() is called with state equal Error', () => {
|
||||
const propsData = {
|
||||
text: 'Error',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-text">Error</span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getBadgeStatus()', () => {
|
||||
it('getBadgeStatus() is called and the value returned is default status', () => {
|
||||
const propsData = {
|
||||
text: 'Another',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-dot ant-badge-status-default"></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is success status', () => {
|
||||
const propsData = {
|
||||
text: 'Active',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-dot ant-badge-status-success"></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is error status', () => {
|
||||
const propsData = {
|
||||
text: 'Disabled',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-dot ant-badge-status-error"></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is processing status', () => {
|
||||
const propsData = {
|
||||
text: 'Migrating',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge-status-dot ant-badge-status-processing"></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is error status', () => {
|
||||
const propsData = {
|
||||
text: 'Alert',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-error"></span><span class="ant-badge-status-text">Alert</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is warning status with state equal Allocated', () => {
|
||||
const propsData = {
|
||||
text: 'Allocated',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text">Allocated</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is success status with state equal Allocated', () => {
|
||||
const propsData = {
|
||||
text: 'Allocated',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
router = common.createMockRouter([{
|
||||
name: 'testRouter1',
|
||||
path: '/publicip',
|
||||
meta: {
|
||||
icon: 'test-router-1'
|
||||
}
|
||||
}])
|
||||
router.push({ name: 'testRouter1' })
|
||||
|
||||
const wrapper = factory({ router: router, props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Allocated</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getBadgeStatus() is called and the value returned is warning status with state equal Created', () => {
|
||||
const propsData = {
|
||||
text: 'Created',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
const wrapper = factory({ props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text">Created</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getTooltip()', () => {
|
||||
it('getTooltip() is called with `$route.path` equal `/vmsnapshot`', () => {
|
||||
const propsData = {
|
||||
text: 'Active',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
router = common.createMockRouter([{
|
||||
name: 'testRouter1',
|
||||
path: '/vmsnapshot',
|
||||
meta: {
|
||||
icon: 'test-router-1'
|
||||
}
|
||||
}])
|
||||
router.push({ name: 'testRouter1' })
|
||||
|
||||
const wrapper = factory({ router: router, props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Active</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getTooltip() is called with `$route.path` equal `/vm`', () => {
|
||||
const propsData = {
|
||||
text: 'Active',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
router = common.createMockRouter([{
|
||||
name: 'testRouter1',
|
||||
path: '/vm',
|
||||
meta: {
|
||||
icon: 'test-router-1'
|
||||
}
|
||||
}])
|
||||
router.push({ name: 'testRouter1' })
|
||||
|
||||
const wrapper = factory({ router: router, props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Active</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getTooltip() is called with `$route.path` equal `/volume`', () => {
|
||||
const propsData = {
|
||||
text: 'Active',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
router = common.createMockRouter([{
|
||||
name: 'testRouter1',
|
||||
path: '/volume',
|
||||
meta: {
|
||||
icon: 'test-router-1'
|
||||
}
|
||||
}])
|
||||
router.push({ name: 'testRouter1' })
|
||||
|
||||
const wrapper = factory({ router: router, props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Active</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getTooltip() is called with `$route.path` equal `/guestnetwork`', () => {
|
||||
const propsData = {
|
||||
text: 'Active',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
router = common.createMockRouter([{
|
||||
name: 'testRouter1',
|
||||
path: '/guestnetwork',
|
||||
meta: {
|
||||
icon: 'test-router-1'
|
||||
}
|
||||
}])
|
||||
router.push({ name: 'testRouter1' })
|
||||
|
||||
const wrapper = factory({ router: router, props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Active</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
|
||||
it('getTooltip() is called with `$route.path` equal `/publicip`', () => {
|
||||
const propsData = {
|
||||
text: 'Active',
|
||||
displayText: true
|
||||
}
|
||||
|
||||
router = common.createMockRouter([{
|
||||
name: 'testRouter1',
|
||||
path: '/publicip',
|
||||
meta: {
|
||||
icon: 'test-router-1'
|
||||
}
|
||||
}])
|
||||
router.push({ name: 'testRouter1' })
|
||||
|
||||
const wrapper = factory({ router: router, props: propsData })
|
||||
const received = wrapper.html()
|
||||
const expected = '<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper" style="display: inline-flex;"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Active</span></span>'
|
||||
|
||||
expect(received).toContain(expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
2939
ui/tests/unit/views/AutogenView.spec.js
Normal file
2939
ui/tests/unit/views/AutogenView.spec.js
Normal file
File diff suppressed because it is too large
Load Diff
686
ui/tests/unit/views/compute/MigrateWizard.spec.js
Normal file
686
ui/tests/unit/views/compute/MigrateWizard.spec.js
Normal file
@ -0,0 +1,686 @@
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you 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 mockAxios from '../../../mock/mockAxios'
|
||||
import MigrateWizard from '@/views/compute/MigrateWizard'
|
||||
import common from '../../../common'
|
||||
import mockData from '../../../mockData/MigrateWizard.mock'
|
||||
|
||||
jest.mock('axios', () => mockAxios)
|
||||
|
||||
let wrapper, i18n, store, mocks
|
||||
|
||||
const state = {}
|
||||
const actions = {
|
||||
AddAsyncJob: jest.fn((jobObject) => {})
|
||||
}
|
||||
mocks = {
|
||||
$message: {
|
||||
error: jest.fn((message) => {})
|
||||
},
|
||||
$notification: {
|
||||
error: jest.fn((message) => {})
|
||||
},
|
||||
$pollJob: jest.fn((obj) => {
|
||||
switch (obj.jobId) {
|
||||
case 'test-job-id-case-1':
|
||||
if ('successMethod' in obj) {
|
||||
obj.successMethod()
|
||||
}
|
||||
break
|
||||
case 'test-job-id-case-2':
|
||||
if ('errorMethod' in obj) {
|
||||
obj.errorMethod()
|
||||
}
|
||||
break
|
||||
case 'test-job-id-case-3':
|
||||
if ('catchMethod' in obj) {
|
||||
obj.catchMethod()
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
i18n = common.createMockI18n('en', mockData.messages)
|
||||
store = common.createMockStore(state, actions)
|
||||
|
||||
const factory = (opts = {}) => {
|
||||
i18n = opts.i18n || i18n
|
||||
store = opts.store || store
|
||||
mocks = opts.mocks || mocks
|
||||
|
||||
return common.createFactory(MigrateWizard, {
|
||||
i18n,
|
||||
store,
|
||||
mocks,
|
||||
props: opts.props || {},
|
||||
data: opts.data || {}
|
||||
})
|
||||
}
|
||||
|
||||
describe('Views > compute > MigrateWizard.vue', () => {
|
||||
jest.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
|
||||
if (wrapper) {
|
||||
wrapper.destroy()
|
||||
}
|
||||
|
||||
if (i18n.locale !== 'en') {
|
||||
i18n.locale = 'en'
|
||||
}
|
||||
})
|
||||
|
||||
describe('Methods', () => {
|
||||
describe('fetchData()', () => {
|
||||
it('check api is called with resource is empty and searchQuery is null', () => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 0,
|
||||
host: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {}
|
||||
}
|
||||
})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'findHostsForMigration',
|
||||
virtualmachineid: undefined,
|
||||
keyword: '',
|
||||
page: 1,
|
||||
pagesize: 10,
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('check api is called with resource.id is null and searchQuery is null', () => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 0,
|
||||
host: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: { id: null }
|
||||
}
|
||||
})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'findHostsForMigration',
|
||||
virtualmachineid: null,
|
||||
keyword: '',
|
||||
page: 1,
|
||||
pagesize: 10,
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('check api is called with resource.id is not null and searchQuery is null', () => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 0,
|
||||
host: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: { id: 'test-id-value' }
|
||||
}
|
||||
})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'findHostsForMigration',
|
||||
virtualmachineid: 'test-id-value',
|
||||
keyword: '',
|
||||
page: 1,
|
||||
pagesize: 10,
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('check api is called with resource.id is not null and searchQuery is not null', () => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 0,
|
||||
host: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({
|
||||
props: { resource: { id: 'test-id-value' } },
|
||||
data: { searchQuery: 'test-query-value' }
|
||||
})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'findHostsForMigration',
|
||||
virtualmachineid: 'test-id-value',
|
||||
keyword: 'test-query-value',
|
||||
page: 1,
|
||||
pagesize: 10,
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('check api is called with params assign by resource, searchQuery, page, pageSize', () => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 0,
|
||||
host: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({
|
||||
props: { resource: { id: 'test-id-value' } },
|
||||
data: {
|
||||
searchQuery: 'test-query-value',
|
||||
page: 2,
|
||||
pageSize: 20
|
||||
}
|
||||
})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'findHostsForMigration',
|
||||
virtualmachineid: 'test-id-value',
|
||||
keyword: 'test-query-value',
|
||||
page: 2,
|
||||
pagesize: 20,
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('check hosts, totalCount when api is called with response result is empty', async (done) => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 0,
|
||||
host: []
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({ props: { resource: {} } })
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(wrapper.vm.hosts).toEqual([])
|
||||
expect(wrapper.vm.totalCount).toEqual(0)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check hosts, totalCount when api is called with response result is not empty', async (done) => {
|
||||
const mockData = {
|
||||
findhostsformigrationresponse: {
|
||||
count: 1,
|
||||
host: [{
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name',
|
||||
suitability: 'test-host-suitability',
|
||||
cpuused: 'test-host-cpuused',
|
||||
memused: 'test-host-memused',
|
||||
select: 'test-host-select'
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
wrapper = factory({ props: { resource: {} } })
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(wrapper.vm.hosts).toEqual([{
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name',
|
||||
suitability: 'test-host-suitability',
|
||||
cpuused: 'test-host-cpuused',
|
||||
memused: 'test-host-memused',
|
||||
select: 'test-host-select'
|
||||
}])
|
||||
expect(wrapper.vm.totalCount).toEqual(1)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check $message.error is called when api is called with throw error', async (done) => {
|
||||
const mockError = 'Error: throw error message'
|
||||
console.error = jest.fn()
|
||||
|
||||
mockAxios.mockRejectedValue(mockError)
|
||||
wrapper = factory({ props: { resource: {} } })
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mocks.$message.error).toHaveBeenCalled()
|
||||
expect(mocks.$message.error).toHaveBeenCalledWith(`${i18n.t('message.load.host.failed')}: ${mockError}`)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('submitForm()', () => {
|
||||
it('check api is called when selectedHost.requiresStorageMotion is true', async (done) => {
|
||||
const mockData = {
|
||||
migratevirtualmachineresponse: {
|
||||
jobid: 'test-job-id'
|
||||
},
|
||||
queryasyncjobresultresponse: {
|
||||
jobstatus: 1,
|
||||
jobresult: {
|
||||
name: 'test-name-value'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id',
|
||||
name: 'test-resource-name'
|
||||
}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: true,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'migrateVirtualMachineWithVolume',
|
||||
hostid: 'test-host-id',
|
||||
virtualmachineid: 'test-resource-id',
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check api is called when selectedHost.requiresStorageMotion is false', async (done) => {
|
||||
const mockData = {
|
||||
migratevirtualmachineresponse: {
|
||||
jobid: 'test-job-id'
|
||||
},
|
||||
queryasyncjobresultresponse: {
|
||||
jobstatus: 1,
|
||||
jobresult: {
|
||||
name: 'test-name-value'
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id',
|
||||
name: 'test-resource-name'
|
||||
}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: false,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mockAxios).toHaveBeenCalled()
|
||||
expect(mockAxios).toHaveBeenCalledWith({
|
||||
url: '/',
|
||||
method: 'GET',
|
||||
data: new URLSearchParams(),
|
||||
params: {
|
||||
command: 'migrateVirtualMachine',
|
||||
hostid: 'test-host-id',
|
||||
virtualmachineid: 'test-resource-id',
|
||||
response: 'json'
|
||||
}
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check store dispatch `AddAsyncJob` and $pollJob have successMethod() is called with requiresStorageMotion is true', async (done) => {
|
||||
const mockData = {
|
||||
migratevirtualmachinewithvolumeresponse: {
|
||||
jobid: 'test-job-id-case-1'
|
||||
},
|
||||
queryasyncjobresultresponse: {
|
||||
jobstatus: 1,
|
||||
jobresult: {
|
||||
name: 'test-name-value'
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id',
|
||||
name: 'test-resource-name'
|
||||
}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: true,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(actions.AddAsyncJob).toHaveBeenCalled()
|
||||
expect(mocks.$pollJob).toHaveBeenCalled()
|
||||
expect(wrapper.emitted()['close-action'][0]).toEqual([])
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check store dispatch `AddAsyncJob` and $pollJob have successMethod() is called with requiresStorageMotion is false', async (done) => {
|
||||
const mockData = {
|
||||
migratevirtualmachineresponse: {
|
||||
jobid: 'test-job-id-case-2'
|
||||
},
|
||||
queryasyncjobresultresponse: {
|
||||
jobstatus: 1,
|
||||
jobresult: {
|
||||
name: 'test-name-value'
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id',
|
||||
name: 'test-resource-name'
|
||||
}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: false,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(actions.AddAsyncJob).toHaveBeenCalled()
|
||||
expect(mocks.$pollJob).toHaveBeenCalled()
|
||||
expect(wrapper.emitted()['close-action'][0]).toEqual([])
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check store dispatch `AddAsyncJob` and $pollJob have errorMethod() is called', async (done) => {
|
||||
const mockData = {
|
||||
migratevirtualmachinewithvolumeresponse: {
|
||||
jobid: 'test-job-id-case-3'
|
||||
},
|
||||
queryasyncjobresultresponse: {
|
||||
jobstatus: 2,
|
||||
jobresult: {
|
||||
errortext: 'test-error-message'
|
||||
}
|
||||
}
|
||||
}
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id',
|
||||
name: 'test-resource-name'
|
||||
}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: true,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(actions.AddAsyncJob).toHaveBeenCalled()
|
||||
expect(mocks.$pollJob).toHaveBeenCalled()
|
||||
expect(wrapper.emitted()['close-action'][0]).toEqual([])
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check store dispatch `AddAsyncJob` and $pollJob have catchMethod() is called', async (done) => {
|
||||
const mockData = {
|
||||
migratevirtualmachinewithvolumeresponse: {
|
||||
jobid: 'test-job-id-case-4'
|
||||
}
|
||||
}
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {
|
||||
id: 'test-resource-id',
|
||||
name: 'test-resource-name'
|
||||
}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: true,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
mockAxios.mockResolvedValue(mockData)
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(actions.AddAsyncJob).toHaveBeenCalled()
|
||||
expect(mocks.$pollJob).toHaveBeenCalled()
|
||||
expect(wrapper.emitted()['close-action'][0]).toEqual([])
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('check $message.error is called when api is called with throw error', async (done) => {
|
||||
const mockError = {
|
||||
message: 'Error: throw error message'
|
||||
}
|
||||
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {}
|
||||
},
|
||||
data: {
|
||||
selectedHost: {
|
||||
requiresStorageMotion: true,
|
||||
id: 'test-host-id',
|
||||
name: 'test-host-name'
|
||||
}
|
||||
}
|
||||
})
|
||||
jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
mockAxios.mockRejectedValue(mockError)
|
||||
|
||||
await wrapper.vm.$nextTick()
|
||||
await wrapper.vm.submitForm()
|
||||
|
||||
setTimeout(() => {
|
||||
expect(mocks.$notification.error).toHaveBeenCalled()
|
||||
expect(mocks.$notification.error).toHaveBeenCalledWith({
|
||||
message: i18n.t('message.request.failed'),
|
||||
description: 'Error: throw error message',
|
||||
duration: 0
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('handleChangePage()', () => {
|
||||
it('check page, pageSize and fetchData() when handleChangePage() is called', () => {
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {}
|
||||
},
|
||||
data: {
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
})
|
||||
const spyFetchData = jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
wrapper.vm.handleChangePage(2, 20)
|
||||
|
||||
expect(wrapper.vm.page).toEqual(2)
|
||||
expect(wrapper.vm.pageSize).toEqual(20)
|
||||
expect(spyFetchData).toBeCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('handleChangePageSize()', () => {
|
||||
it('check page, pageSize and fetchData() when handleChangePageSize() is called', () => {
|
||||
wrapper = factory({
|
||||
props: {
|
||||
resource: {}
|
||||
},
|
||||
data: {
|
||||
page: 1,
|
||||
pageSize: 10
|
||||
}
|
||||
})
|
||||
const spyFetchData = jest.spyOn(wrapper.vm, 'fetchData').mockImplementation(() => {})
|
||||
|
||||
wrapper.vm.$nextTick(() => {
|
||||
wrapper.vm.handleChangePageSize(2, 20)
|
||||
|
||||
expect(wrapper.vm.page).toEqual(2)
|
||||
expect(wrapper.vm.pageSize).toEqual(20)
|
||||
expect(spyFetchData).toBeCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user