diff --git a/src/Test.vue b/src/Test.vue index adef5052..83a0efde 100644 --- a/src/Test.vue +++ b/src/Test.vue @@ -11,12 +11,14 @@ import { useRoute, useRouter } from 'vue-router' import axios from 'axios' import { ref } from 'vue' +import indexedDBUtils from '@/indexedDB' export default { name: 'Test', data () { return { count: 0, - obj: { id: 1, title: 'title' } + obj: { id: 1, title: 'title' }, + indexedDBValue: null } }, methods: { @@ -35,6 +37,12 @@ export default { axios.get('/api/getCount').then(response => { this.count = response.data }) + }, + async setIndexedDBValue () { + await indexedDBUtils.selectTable('test').put({ id: 1, name: 'test' }) + }, + async getIndexedDBValue () { + this.indexedDBValue = await indexedDBUtils.selectTable('test').get(1) } }, setup () { diff --git a/src/indexedDB/index.js b/src/indexedDB/index.js index 6fc7e9dd..1c984855 100644 --- a/src/indexedDB/index.js +++ b/src/indexedDB/index.js @@ -1,8 +1,19 @@ import { dbName, dbGeoDataTableName, dbDrilldownTableConfig } from '@/utils/constants' import Dexie from 'dexie' +/* https://dexie.org/ */ -export const db = new Dexie(dbName) -db.version(2).stores({ +const db = new Dexie(dbName) +db.version(3).stores({ [dbGeoDataTableName]: '++name, geo', - [dbDrilldownTableConfig]: '++id, config' + [dbDrilldownTableConfig]: '++id, config', + test: '++id, name' }) +function selectTable (tableName) { + return db[tableName] +} + +const indexedDBUtils = { + db, + selectTable +} +export default indexedDBUtils diff --git a/src/store/modules/user.js b/src/store/modules/user.js index 6577ed44..1c05db2c 100644 --- a/src/store/modules/user.js +++ b/src/store/modules/user.js @@ -5,7 +5,7 @@ import { ElMessage } from 'element-plus' // dependent on utc plugin import { storageKey, dbDrilldownTableConfig } from '@/utils/constants' import { getConfigVersion } from '@/utils/tools' import { api } from '@/utils/api' -import { db } from '@/indexedDB' +import indexedDBUtils from '@/indexedDB' const user = { state () { @@ -92,7 +92,7 @@ const user = { if (res.code === 200 && res.page.list && res.page.list.length > 0) { // 从接口返回整体配置,再读取用户缓存,将对应条目覆盖,作为使用的配置 const defaultConfigs = JSON.parse(res.page.list[0].cvalue) - await db[dbDrilldownTableConfig].put({ + await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({ id: 'default', version: defaultConfigs.version, config: defaultConfigs.config @@ -100,7 +100,7 @@ const user = { const userId = localStorage.getItem(storageKey.userId) const oldVersion = await getConfigVersion(userId) if (oldVersion !== defaultConfigs.version) { - db[dbDrilldownTableConfig].delete(userId) + indexedDBUtils.selectTable(dbDrilldownTableConfig).delete(userId) } } }) diff --git a/src/utils/constants.js b/src/utils/constants.js index ebdd96e2..96d4807d 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -1,6 +1,8 @@ export const defaultPageSize = 20 +// indexedDB库名 export const dbName = 'cn-db' +// indexedDB表名 export const dbGeoDataTableName = 'geodata' export const dbDrilldownTableConfig = 'cn-drilldown-table-config' export const storageKey = { diff --git a/src/utils/tools.js b/src/utils/tools.js index aded6428..1b6d2e80 100644 --- a/src/utils/tools.js +++ b/src/utils/tools.js @@ -5,8 +5,7 @@ import { storageKey, iso36112, topDomain, echartsFontSize, dbGeoDataTableName, n import { getIso36112JsonData, getDictList } from '@/utils/api' import { format } from 'echarts' import router from '@/router' -import { db } from '@/indexedDB' -import { useRoute } from 'vue-router' +import indexedDBUtils from '@/indexedDB' export const tableSort = { // 是否需要排序 @@ -488,11 +487,11 @@ export function loadGeoData () { keys.push(storageKey.iso36112Capital) keys.push(storageKey.iso36112WorldLow) keys.forEach(async k => { - const queryData = await db[dbGeoDataTableName].get({ name: k }) + const queryData = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: k }) if (!queryData) { const data = await getIso36112JsonData(iso36112[k]) if (data) { - db[dbGeoDataTableName].add({ + indexedDBUtils.selectTable(dbGeoDataTableName).add({ name: k, geo: data }) @@ -505,14 +504,14 @@ export function loadGeoData () { * 使用indexedDB缓存地图数据 * */ export async function getGeoData (key) { - const data = await db[dbGeoDataTableName].get({ name: key }) + const data = await indexedDBUtils.selectTable(dbGeoDataTableName).get({ name: key }) if (data) { return data.geo } else { if (iso36112[key]) { const d = await getIso36112JsonData(iso36112[key]) if (d) { - db[dbGeoDataTableName].add({ + indexedDBUtils.selectTable(dbGeoDataTableName).add({ name: key, geo: d }) @@ -937,7 +936,7 @@ export async function getDefaultCurTab (tableType, metric, columnName) { export async function readDrilldownTableConfigByUser () { // 获取用户定制的自定义配置 const userId = localStorage.getItem(storageKey.userId) - const userLocalConfig = await db[dbDrilldownTableConfig].get({ id: userId }) + const userLocalConfig = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: userId }) let defaultDrillDownTableConfigs = [] if (userLocalConfig) { defaultDrillDownTableConfigs = userLocalConfig.config @@ -946,15 +945,15 @@ export async function readDrilldownTableConfigByUser () { } export async function getConfigVersion (id) { - let defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: id }) + let defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: id }) if (!defaultConfigInDb) { - defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' }) + defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' }) } return defaultConfigInDb.version || '' } export async function combineDrilldownTableWithUserConfig () { - const defaultConfigInDb = await db[dbDrilldownTableConfig].get({ id: 'default' }) + const defaultConfigInDb = await indexedDBUtils.selectTable(dbDrilldownTableConfig).get({ id: 'default' }) const defaultConfigGroup = defaultConfigInDb ? defaultConfigInDb.config : [] const currentUserConfigGroup = await readDrilldownTableConfigByUser() if (defaultConfigGroup && currentUserConfigGroup && currentUserConfigGroup.length > 0) { diff --git a/src/views/charts2/charts/networkOverview/NetworkOverviewTabs.vue b/src/views/charts2/charts/networkOverview/NetworkOverviewTabs.vue index 82608083..08c6cc3e 100644 --- a/src/views/charts2/charts/networkOverview/NetworkOverviewTabs.vue +++ b/src/views/charts2/charts/networkOverview/NetworkOverviewTabs.vue @@ -215,8 +215,8 @@ import unitConvert from '@/utils/unit-convert' import { getChainRatio, computeScore, urlParamsHandler, overwriteUrl, readDrilldownTableConfigByUser, combineDrilldownTableWithUserConfig, getDnsMapData, handleSpecialValue, getConfigVersion } from '@/utils/tools' import { getSecond } from '@/utils/date-util' import chartMixin from '@/views/charts2/chart-mixin' -import { db } from '@/indexedDB' import _ from 'lodash' +import indexedDBUtils from '@/indexedDB' export default { name: 'NetworkOverviewTabs', @@ -1729,7 +1729,7 @@ export default { version = await getConfigVersion('default') } // 更新缓存中的配置 - await db[dbDrilldownTableConfig].put({ + await indexedDBUtils.selectTable(dbDrilldownTableConfig).put({ id: this.userId, version: version, config: this.$_.cloneDeep(curUserConfigGroup) diff --git a/test/Test.test.js b/test/Test.test.js index 1fb675ad..f8a30a55 100644 --- a/test/Test.test.js +++ b/test/Test.test.js @@ -7,6 +7,7 @@ import Test from '../src/Test' import { mount } from '@vue/test-utils' import { getNameByEventType } from '@/utils/tools' import axios from 'axios' +import indexedDBUtils from '@/indexedDB' // 模拟的axios返回数据 const mockId = { data: 2 } @@ -33,7 +34,6 @@ describe('单元测试demo', () => { await button.trigger('click') // 断言点击按钮后文本dom的内容是否是'2' expect(textNode.text()).toBe('2') - /* 更多断言类型:https://jestjs.io/docs/expect */ }) test('Vue组件--获取路由中的参数', async () => { @@ -49,7 +49,7 @@ describe('单元测试demo', () => { test('Vue组件--模拟获取localstorage/sessionStorage的内容', async () => { require('vue-router').useRoute.mockReturnValue({ query: {} }) require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } }) - // 模拟getItem + // 模拟localStorage的getItem jest.spyOn(localStorage.__proto__, 'getItem').mockImplementation(key => key) // 加载vue组件,获得实例 const wrapper = mount(Test) @@ -105,6 +105,20 @@ describe('单元测试demo', () => { expect(wrapper.vm.obj).toEqual({ id: 2, title: 'title2' }) }) }) + test('Vue组件--模拟indexedDB操作', async () => { + require('vue-router').useRoute.mockReturnValue({ query: {} }) + require('vue-router').useRouter.mockReturnValue({ currentRoute: { value: { path: '/' } } }) + // 加载vue组件,获得实例 + const wrapper = mount(Test) + // 模拟indexedDB的内容 + indexedDBUtils.selectTable.mockReturnValue({ + put: jest.fn(), + get: jest.fn().mockResolvedValue({ a: 1 }) + }) + await wrapper.vm.setIndexedDBValue() + await wrapper.vm.getIndexedDBValue() + expect(wrapper.vm.indexedDBValue).toEqual({ a: 1 }) + }) test('js方法--getNameByEventType', async () => { expect(getNameByEventType('http error')).toBe('http error ratio') }) diff --git a/test/init.js b/test/init.js index bdd7e894..4963223f 100644 --- a/test/init.js +++ b/test/init.js @@ -27,6 +27,8 @@ jest.mock('vue-router', () => { }) /* 模拟axios */ jest.mock('axios') +/* 模拟indexedDB工具 */ +jest.mock('@/indexedDB') /* 模拟$t */ config.global.mocks.$t = key => key /* 模拟$route,具体用例中需要不同值时重写覆盖即可 */ diff --git a/test/views/charts2/charts/networkOverview/NetworkOverviewLine.test.js b/test/views/charts2/charts/networkOverview/NetworkOverviewLine.test.js index f9dcebd0..fed43ce7 100644 --- a/test/views/charts2/charts/networkOverview/NetworkOverviewLine.test.js +++ b/test/views/charts2/charts/networkOverview/NetworkOverviewLine.test.js @@ -5,21 +5,23 @@ import axios from 'axios' const mockGet = { data: {"status":200,"code":200,"success":true,"message":null,"formatType":"json","data":{"resultType":"object","result":[{"type":"bytes","totalBitsRate":{"values":[[1673247564,"96801019.52"]],"analysis":{"avg":"112042808.24","max":"301842105.76","min":"52096324","p95":"168089003.35199997"}},"inboundBitsRate":{"values":[[1673247564,"11814508.48"]],"analysis":{"avg":"18587597.36","max":"137528138.88","min":"3181142.88","p95":"49561521.447999954"}},"outboundBitsRate":{"values":[[1673247564,"84282965.52"]],"analysis":{"avg":"87557861.44","max":"290402258","min":"45337684.48","p95":"121041718.81199999"}},"internalBitsRate":{"values":[[1673247564,"9125.12"]],"analysis":{"avg":"278114.32","max":"2215460.48","min":"0","p95":"923494.5719999998"}},"throughBitsRate":{"values":[[1673247564,"694420.48"]],"analysis":{"avg":"5619235.12","max":"42455480.24","min":"262607.76","p95":"13559588.195999999"}},"other":{"values":[[1673247564,"0.00"]],"analysis":{"avg":"0.01","max":"0.08","min":"0.00","p95":"0.08"}}},{"type":"packets","totalPacketsRate":{"values":[[1673247564,"12077.53"]],"analysis":{"avg":"14062.37","max":"32840.42","min":"6564.17","p95":"20923.167999999987"}},"inboundPacketsRate":{"values":[[1673247564,"3865.58"]],"analysis":{"avg":"4241.61","max":"15460.03","min":"1918.22","p95":"8549.799999999997"}},"outboundPacketsRate":{"values":[[1673247564,"8118.89"]],"analysis":{"avg":"9170.98","max":"27134.58","min":"4510.25","p95":"13690.540999999996"}},"internalPacketsRate":{"values":[[1673247564,"15.89"]],"analysis":{"avg":"35.95","max":"276.47","min":"0.00","p95":"122.49749999999999"}},"throughPacketsRate":{"values":[[1673247564,"77.17"]],"analysis":{"avg":"613.82","max":"3768.56","min":"42.92","p95":"1279.757499999999"}},"other":{"values":[[1673247564,"0.00"]],"analysis":{"avg":"0","max":"0.01","min":"0.00","p95":"0.01"}}},{"type":"sessions","totalSessionsRate":{"values":[[1673247564,"29.92"]],"analysis":{"avg":"29.89","max":"29.92","min":"29.67","p95":"29.92"}}}]},"msg":"OK"} } +const timeFilter = { + dateRangeValue: -1, + startTime: 1673244000000, + endTime: 1673247600000 +} +const chart = {"id":1,"name":"network overview line","i18n":"","panelId":1,"pid":0,"type":102,"x":0,"y":0,"w":19,"h":6,"params":{},"cby":1,"ctime":"2022-07-06 16:59:22","uby":1,"utime":"2022-07-06 16:59:22","remark":"","state":1,"system":0,"buildIn":0,"uuser":{"id":1,"name":null,"username":"admin","salt":null,"lang":null,"theme":null,"lastLoginIp":null,"lastLoginTime":null,"ctime":null,"cby":null,"email":null,"mobile":null,"status":null,"source":null,"buildIn":null,"roleIds":null,"usergroupIds":null,"roles":null,"apiKeyId":null},"cuser":{"id":1,"name":null,"username":"admin","salt":null,"lang":null,"theme":null,"lastLoginIp":null,"lastLoginTime":null,"ctime":null,"cby":null,"email":null,"mobile":null,"status":null,"source":null,"buildIn":null,"roleIds":null,"usergroupIds":null,"roles":null,"apiKeyId":null},"children":[],"parent":null,"panel":{"id":1,"name":"Network Overview","i18n":null,"type":null,"params":null,"cby":null,"ctime":null,"uby":null,"utime":null,"remark":null,"state":null,"buildIn":null,"uuser":null,"cuser":null},"i":1,"category":"echarts","firstShow":false,"moved":false} -describe('NetworkOverviewLine.vue测试', () => { - test('Metric=Bits/s', async () => { +describe('views/charts2/charts/networkOverview/NetworkOverviewLine.vue测试', () => { + test('Metric=Bits/s,点击第三个tab', async () => { require('vue-router').useRoute.mockReturnValue({ query: {} }) // 模拟axios返回数据 axios.get.mockResolvedValue(mockGet) // 加载vue组件,获得实例 const wrapper = mount(NetworkOverviewLine, { propsData: { - timeFilter: { - dateRangeValue: -1, - startTime: 1673244000000, - endTime: 1673247600000 - }, - chart: {"id":1,"name":"network overview line","i18n":"","panelId":1,"pid":0,"type":102,"x":0,"y":0,"w":19,"h":6,"params":{},"cby":1,"ctime":"2022-07-06 16:59:22","uby":1,"utime":"2022-07-06 16:59:22","remark":"","state":1,"system":0,"buildIn":0,"uuser":{"id":1,"name":null,"username":"admin","salt":null,"lang":null,"theme":null,"lastLoginIp":null,"lastLoginTime":null,"ctime":null,"cby":null,"email":null,"mobile":null,"status":null,"source":null,"buildIn":null,"roleIds":null,"usergroupIds":null,"roles":null,"apiKeyId":null},"cuser":{"id":1,"name":null,"username":"admin","salt":null,"lang":null,"theme":null,"lastLoginIp":null,"lastLoginTime":null,"ctime":null,"cby":null,"email":null,"mobile":null,"status":null,"source":null,"buildIn":null,"roleIds":null,"usergroupIds":null,"roles":null,"apiKeyId":null},"children":[],"parent":null,"panel":{"id":1,"name":"Network Overview","i18n":null,"type":null,"params":null,"cby":null,"ctime":null,"uby":null,"utime":null,"remark":null,"state":null,"buildIn":null,"uuser":null,"cuser":null},"i":1,"category":"echarts","firstShow":false,"moved":false} + timeFilter, + chart } }) const textNode0 = await wrapper.get('[test-id="tabContent0"]') @@ -45,13 +47,9 @@ describe('NetworkOverviewLine.vue测试', () => { // 加载vue组件,获得实例 const wrapper = mount(NetworkOverviewLine, { propsData: { - timeFilter: { - dateRangeValue: -1, - startTime: 1673244000000, - endTime: 1673247600000 - }, - metric: 'Packets/s', - chart: {"id":1,"name":"network overview line","i18n":"","panelId":1,"pid":0,"type":102,"x":0,"y":0,"w":19,"h":6,"params":{},"cby":1,"ctime":"2022-07-06 16:59:22","uby":1,"utime":"2022-07-06 16:59:22","remark":"","state":1,"system":0,"buildIn":0,"uuser":{"id":1,"name":null,"username":"admin","salt":null,"lang":null,"theme":null,"lastLoginIp":null,"lastLoginTime":null,"ctime":null,"cby":null,"email":null,"mobile":null,"status":null,"source":null,"buildIn":null,"roleIds":null,"usergroupIds":null,"roles":null,"apiKeyId":null},"cuser":{"id":1,"name":null,"username":"admin","salt":null,"lang":null,"theme":null,"lastLoginIp":null,"lastLoginTime":null,"ctime":null,"cby":null,"email":null,"mobile":null,"status":null,"source":null,"buildIn":null,"roleIds":null,"usergroupIds":null,"roles":null,"apiKeyId":null},"children":[],"parent":null,"panel":{"id":1,"name":"Network Overview","i18n":null,"type":null,"params":null,"cby":null,"ctime":null,"uby":null,"utime":null,"remark":null,"state":null,"buildIn":null,"uuser":null,"cuser":null},"i":1,"category":"echarts","firstShow":false,"moved":false} + timeFilter, + chart, + metric: 'Packets/s' } }) const textNode0 = await wrapper.get('[test-id="tabContent0"]') @@ -64,4 +62,22 @@ describe('NetworkOverviewLine.vue测试', () => { resolve() }, 200)) }) + test('Metric=Sessions/s', async () => { + require('vue-router').useRoute.mockReturnValue({ query: {} }) + // 模拟axios返回数据 + axios.get.mockResolvedValue(mockGet) + // 加载vue组件,获得实例 + const wrapper = mount(NetworkOverviewLine, { + propsData: { + timeFilter, + chart, + metric: 'Sessions/s' + } + }) + const textNode0 = await wrapper.get('[test-id="tabContent0"]') + await new Promise(resolve => setTimeout(() => { + expect(textNode0.text()).toEqual('29.89sessions/s') + resolve() + }, 200)) + }) })