@kalisio/kdk 2.1.9 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.test.sh +42 -10
- package/README.md +2 -2
- package/core/api/application.js +6 -1
- package/core/api/authentication.js +17 -1
- package/core/api/db.js +7 -2
- package/core/api/hooks/hooks.authentication.js +4 -2
- package/core/api/hooks/hooks.authorisations.js +12 -2
- package/core/api/hooks/hooks.model.js +5 -5
- package/core/api/hooks/hooks.organisations.js +0 -4
- package/core/api/services/account/account.hooks.js +10 -6
- package/core/api/services/account/account.service.js +1 -1
- package/{map/api/services/geocoder/geocoder.hooks.js → core/api/services/import-export/import-export.hooks.js} +7 -5
- package/core/api/services/import-export/import-export.service.js +11 -0
- package/core/api/services/index.js +13 -1
- package/core/api/services/users/users.hooks.js +2 -3
- package/core/client/api.js +16 -14
- package/core/client/capabilities.js +6 -2
- package/core/client/components/KContent.vue +11 -1
- package/core/client/components/KDialog.vue +17 -15
- package/core/client/components/KSponsor.vue +1 -1
- package/core/client/components/KTextArea.vue +5 -1
- package/core/client/components/app/KAbout.vue +1 -2
- package/core/client/components/app/KWelcome.vue +3 -5
- package/core/client/components/chart/KTimeSeriesChart.vue +24 -37
- package/core/client/components/collection/KColumn.vue +20 -17
- package/core/client/components/editor/KModalEditor.vue +0 -2
- package/core/client/components/form/KChipsField.vue +12 -2
- package/core/client/components/form/KColorField.vue +12 -2
- package/core/client/components/form/KColorScaleField.vue +12 -2
- package/core/client/components/form/KDateTimeRangeField.vue +12 -2
- package/core/client/components/form/KDatetimeField.vue +12 -2
- package/core/client/components/form/KEmailField.vue +12 -2
- package/core/client/components/form/KFileField.vue +12 -2
- package/core/client/components/form/KForm.vue +43 -9
- package/core/client/components/form/KIconField.vue +12 -2
- package/core/client/components/form/KItemField.vue +25 -4
- package/core/client/components/form/KNumberField.vue +12 -2
- package/core/client/components/form/KOptionsField.vue +12 -2
- package/core/client/components/form/KPasswordField.vue +12 -2
- package/core/client/components/form/KPhoneField.vue +13 -3
- package/core/client/components/form/KPropertyItemField.vue +12 -2
- package/core/client/components/form/KResolutionField.vue +126 -0
- package/core/client/components/form/KRoleField.vue +12 -2
- package/core/client/components/form/KSelectField.vue +14 -4
- package/core/client/components/form/KTextField.vue +12 -2
- package/core/client/components/form/KTextareaField.vue +13 -3
- package/core/client/components/form/KToggleField.vue +12 -2
- package/core/client/components/form/KTokenField.vue +12 -2
- package/core/client/components/form/KUnitField.vue +12 -2
- package/core/client/components/form/KUrlField.vue +12 -2
- package/core/client/components/input/KIconChooser.vue +10 -12
- package/core/client/components/input/KPalette.vue +2 -1
- package/core/client/components/layout/KPage.vue +5 -4
- package/core/client/components/layout/KWindow.vue +10 -10
- package/core/client/components/media/KColorScale.vue +26 -20
- package/core/client/components/media/KImageViewer.vue +57 -33
- package/core/client/components/media/KShape.vue +14 -103
- package/core/client/components/screen/KRegisterScreen.vue +0 -1
- package/core/client/components/screen/KScreenFooter.vue +0 -18
- package/core/client/components/team/KAddMember.vue +16 -22
- package/core/client/components/team/KGroupsActivity.vue +14 -0
- package/core/client/components/team/KMembersActivity.vue +12 -0
- package/core/client/components/team/KTagsActivity.vue +14 -0
- package/core/client/components/time/KDateTime.vue +23 -7
- package/core/client/components/time/KTimeControl.vue +142 -0
- package/core/client/components/tool/KExportTool.vue +57 -0
- package/core/client/composables/collection.js +0 -1
- package/core/client/composables/pwa.js +0 -1
- package/core/client/composables/schema.js +1 -1
- package/core/client/composables/session.js +30 -6
- package/core/client/exporter.js +141 -0
- package/core/client/i18n/core_en.json +91 -23
- package/core/client/i18n/core_fr.json +92 -23
- package/core/client/index.js +3 -0
- package/core/client/layout.js +34 -14
- package/core/client/local-storage.js +8 -6
- package/core/client/mixins/index.js +0 -1
- package/core/client/mixins/mixin.base-field.js +24 -2
- package/core/client/mixins/mixin.object-proxy.js +0 -1
- package/core/client/search.js +2 -1
- package/core/client/services/index.js +2 -1
- package/core/client/services/local-settings.service.js +4 -4
- package/core/client/theme.js +3 -3
- package/core/client/time.js +4 -0
- package/core/client/units.js +149 -4
- package/core/client/utils/index.js +13 -6
- package/core/client/utils/utils.account.js +1 -1
- package/core/client/utils/utils.colors.js +43 -0
- package/core/client/utils/utils.platform.js +0 -1
- package/core/client/utils/utils.pwa.js +14 -14
- package/core/client/utils/utils.session.js +1 -1
- package/core/client/utils/utils.shapes.js +270 -0
- package/core/client/utils/utils.time.js +37 -0
- package/core/common/permissions.js +3 -0
- package/core/common/schemas/settings.update.json +50 -29
- package/extras/css/core.variables.scss +3 -1
- package/extras/tours/map/navigation-bar.js +17 -15
- package/extras/tours/map/timeline.js +33 -33
- package/map/api/config/categories.cjs +4 -1
- package/map/api/hooks/hooks.catalog.js +39 -0
- package/map/api/hooks/hooks.features.js +23 -3
- package/map/api/hooks/hooks.query.js +31 -10
- package/map/api/models/projects.model.mongodb.js +8 -0
- package/map/api/services/catalog/catalog.hooks.js +5 -3
- package/map/api/services/features/features.hooks.js +18 -6
- package/map/api/services/index.js +22 -6
- package/map/api/services/projects/projects.hooks.js +118 -0
- package/map/client/capture.js +16 -0
- package/map/client/cesium/utils/index.js +3 -0
- package/map/client/cesium/utils/utils.events.js +30 -0
- package/map/client/cesium/utils/utils.popup.js +17 -0
- package/map/client/cesium/{utils.js → utils/utils.style.js} +53 -49
- package/map/client/components/KCapture.vue +50 -0
- package/map/client/components/KCaptureTextArea.vue +53 -0
- package/map/client/components/KCompass.vue +2 -2
- package/map/client/components/KFeaturesChart.vue +1 -1
- package/map/client/components/KFeaturesFilter.vue +2 -2
- package/map/client/components/KLayerStyleForm.vue +256 -430
- package/map/client/components/KLevelSlider.vue +1 -1
- package/map/client/components/KNorth.vue +31 -0
- package/map/client/components/KProjectMenu.vue +88 -0
- package/map/client/components/KTimezoneMap.vue +36 -23
- package/map/client/components/catalog/KAddLayer.vue +3 -4
- package/map/client/components/catalog/KConnectLayer.vue +16 -4
- package/map/client/components/catalog/KCreateLayer.vue +1 -2
- package/map/client/components/catalog/KCreateProject.vue +100 -0
- package/map/client/components/catalog/KCreateView.vue +25 -2
- package/map/client/components/catalog/KLayersPanel.vue +24 -27
- package/map/client/components/catalog/KLayersSelector.vue +1 -1
- package/map/client/components/catalog/KProjectEditor.vue +91 -0
- package/map/client/components/catalog/KProjectManager.vue +60 -0
- package/map/client/components/catalog/KProjectSelector.vue +38 -0
- package/map/client/components/catalog/KProjectsPanel.vue +153 -0
- package/map/client/components/catalog/KSelectLayers.vue +96 -0
- package/map/client/components/catalog/KSelectViews.vue +96 -0
- package/map/client/components/catalog/KViewsPanel.vue +66 -30
- package/map/client/components/form/KDirectionField.vue +24 -5
- package/map/client/components/form/KLayerCategoryField.vue +12 -2
- package/map/client/components/form/KLocationField.vue +20 -5
- package/map/client/components/form/KOwsLayerField.vue +12 -2
- package/map/client/components/form/KOwsServiceField.vue +12 -2
- package/map/client/components/form/KSelectLayersField.vue +159 -0
- package/map/client/components/form/KSelectViewsField.vue +121 -0
- package/map/client/components/form/KTimezoneField.vue +24 -17
- package/map/client/components/legend/KColorScaleLegend.vue +1 -1
- package/map/client/components/legend/KLayerLegend.vue +61 -0
- package/map/client/components/legend/KLegend.vue +45 -44
- package/map/client/components/legend/KLegendRenderer.vue +5 -3
- package/map/client/components/legend/KSymbolsLegend.vue +12 -10
- package/map/client/components/legend/KVariablesLegend.vue +78 -0
- package/map/client/components/location/KGeocodersFilter.vue +2 -4
- package/map/client/components/location/KLocationMap.vue +48 -17
- package/map/client/components/location/KLocationSearch.vue +13 -3
- package/map/client/components/tools/KSearchTool.vue +17 -12
- package/map/client/components/widget/KElevationProfile.vue +16 -19
- package/map/client/components/widget/KMapillaryViewer.vue +21 -22
- package/map/client/components/widget/KTimeSeries.vue +35 -23
- package/map/client/composables/activity.js +15 -2
- package/map/client/composables/catalog.js +66 -0
- package/map/client/composables/highlight.js +56 -20
- package/map/client/composables/index.js +2 -0
- package/map/client/composables/location.js +25 -18
- package/map/client/composables/project.js +122 -0
- package/map/client/geolocation.js +1 -1
- package/map/client/globe.js +2 -0
- package/map/client/i18n/map_en.json +123 -76
- package/map/client/i18n/map_fr.json +124 -72
- package/map/client/index.js +3 -0
- package/map/client/init.js +17 -0
- package/map/client/leaflet/GSMaPLayer.js +16 -17
- package/map/client/leaflet/ShapeMarker.js +40 -0
- package/map/client/leaflet/TiledFeatureLayer.js +1 -1
- package/map/client/leaflet/TiledMeshLayer.js +11 -15
- package/map/client/leaflet/TiledWindLayer.js +6 -10
- package/map/client/leaflet/utils/index.js +4 -0
- package/map/client/leaflet/utils/utils.events.js +41 -0
- package/map/client/leaflet/utils/utils.popup.js +21 -0
- package/map/client/leaflet/utils/utils.style.js +191 -0
- package/map/client/leaflet/utils/utils.tiles.js +87 -0
- package/map/client/map.js +2 -0
- package/map/client/mixins/globe/mixin.base-globe.js +29 -21
- package/map/client/mixins/globe/mixin.geojson-layers.js +132 -69
- package/map/client/mixins/globe/mixin.popup.js +2 -1
- package/map/client/mixins/globe/mixin.style.js +6 -4
- package/map/client/mixins/globe/mixin.tooltip.js +8 -3
- package/map/client/mixins/map/mixin.base-map.js +13 -11
- package/map/client/mixins/map/mixin.edit-layers.js +15 -15
- package/map/client/mixins/map/mixin.forecast-layers.js +3 -1
- package/map/client/mixins/map/mixin.geojson-layers.js +56 -20
- package/map/client/mixins/map/mixin.georaster-layers.js +4 -11
- package/map/client/mixins/map/mixin.heatmap-layers.js +1 -1
- package/map/client/mixins/map/mixin.popup.js +2 -1
- package/map/client/mixins/map/mixin.style.js +4 -67
- package/map/client/mixins/map/mixin.tiled-mesh-layers.js +2 -1
- package/map/client/mixins/map/mixin.tiled-wind-layers.js +4 -2
- package/map/client/mixins/map/mixin.tooltip.js +2 -1
- package/map/client/mixins/mixin.activity.js +66 -191
- package/map/client/mixins/mixin.catalog-panel.js +6 -6
- package/map/client/mixins/mixin.context.js +12 -9
- package/map/client/mixins/mixin.feature-service.js +29 -300
- package/map/client/mixins/mixin.weacast.js +11 -17
- package/map/client/pixi-utils.js +1 -1
- package/map/client/planets.js +58 -0
- package/map/client/utils/index.js +6 -0
- package/map/client/utils/utils.capture.js +176 -0
- package/map/client/utils/utils.catalog.js +149 -0
- package/map/client/utils/utils.features.js +364 -0
- package/map/client/utils/utils.js +0 -151
- package/map/client/utils/utils.layers.js +174 -0
- package/map/client/utils/utils.location.js +91 -23
- package/map/client/utils/utils.project.js +8 -0
- package/map/client/utils/utils.schema.js +0 -1
- package/map/client/utils/utils.style.js +297 -0
- package/map/client/utils.all.js +2 -2
- package/map/client/utils.globe.js +1 -1
- package/map/client/utils.map.js +1 -1
- package/map/common/permissions.js +2 -0
- package/map/common/schemas/capture.create.json +132 -0
- package/map/common/schemas/projects.create.json +52 -0
- package/map/common/schemas/projects.update.json +52 -0
- package/package.json +6 -5
- package/test/api/core/account.test.js +20 -0
- package/test/api/core/config/default.cjs +16 -3
- package/test/api/core/import-export.test.js +86 -0
- package/test/api/core/test-log-2024-01-04.log +14 -0
- package/test/api/map/catalog.test.js +164 -0
- package/test/api/map/index.test.js +25 -61
- package/test/api/map/test-log-2024-01-04.log +2 -0
- package/test/api/map/test-log-2024-01-11.log +1 -0
- package/test/api/map/test-log-2024-01-25.log +19 -0
- package/test/client/core/layout.js +25 -5
- package/test/client/core/utils.js +7 -0
- package/test/client/map/catalog.js +78 -1
- package/test/client/map/time.js +2 -1
- package/core/client/components/screen/KEndpointScreen.vue +0 -80
- package/core/client/mixins/mixin.account.js +0 -61
- package/extras/icons/kdk.png +0 -0
- package/map/api/services/geocoder/geocoder.service.js +0 -79
- package/map/client/components/KCaptureToolbar.vue +0 -155
- package/map/client/components/KColorLegend.vue +0 -349
- package/map/client/components/KTimeline.vue +0 -293
- package/map/client/components/KUrlLegend.vue +0 -122
- package/map/client/leaflet/utils.js +0 -246
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import chai from 'chai'
|
|
2
|
+
import chailint from 'chai-lint'
|
|
3
|
+
import core, { kdk, hooks } from '../../../core/api/index.js'
|
|
4
|
+
|
|
5
|
+
const { util, expect } = chai
|
|
6
|
+
|
|
7
|
+
describe('core:import-export', () => {
|
|
8
|
+
let app, server, port, usersService, storageService, importExportService
|
|
9
|
+
|
|
10
|
+
before(async () => {
|
|
11
|
+
chailint(chai, util)
|
|
12
|
+
app = kdk()
|
|
13
|
+
// Register log hook
|
|
14
|
+
app.hooks({ error: { all: hooks.log } })
|
|
15
|
+
port = app.get('port')
|
|
16
|
+
await app.db.connect()
|
|
17
|
+
await app.db.instance.dropDatabase()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('registers the services', async () => {
|
|
21
|
+
await app.configure(core)
|
|
22
|
+
// Ensure the users service exist
|
|
23
|
+
usersService = app.getService('users')
|
|
24
|
+
expect(usersService).toExist()
|
|
25
|
+
// Ensure the storage service exist
|
|
26
|
+
storageService = app.getService('storage')
|
|
27
|
+
expect(storageService).toExist()
|
|
28
|
+
// Ensure the expoter service exist
|
|
29
|
+
importExportService = app.getService('import-export')
|
|
30
|
+
expect(importExportService).toExist()
|
|
31
|
+
// Now app is configured launch the server
|
|
32
|
+
server = await app.listen(port)
|
|
33
|
+
await new Promise(resolve => server.once('listening', () => resolve()))
|
|
34
|
+
})
|
|
35
|
+
// Let enough time to process
|
|
36
|
+
.timeout(10000)
|
|
37
|
+
|
|
38
|
+
it('create a user collection', () => {
|
|
39
|
+
const users = []
|
|
40
|
+
for (let i = 0; i < 5000; i++) {
|
|
41
|
+
users.push({
|
|
42
|
+
email: `kalisio${i}@kalisio.xyz`,
|
|
43
|
+
password: 'Pass;word1',
|
|
44
|
+
description: 'Description for kalisio$[i}',
|
|
45
|
+
name: `user${i}`
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
return usersService._create(users, { noVerificationEmail: true })
|
|
49
|
+
})
|
|
50
|
+
// Let enough time to process
|
|
51
|
+
.timeout(50000)
|
|
52
|
+
|
|
53
|
+
it('export users collection in json', async () => {
|
|
54
|
+
const response = await importExportService.create({
|
|
55
|
+
method: 'export',
|
|
56
|
+
servicePath: 'api/users',
|
|
57
|
+
transform: {
|
|
58
|
+
omit: ['_id']
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
expect(response.SignedUrl).toExist()
|
|
62
|
+
await storageService.remove('import-export/' + response.id)
|
|
63
|
+
})
|
|
64
|
+
.timeout(30000)
|
|
65
|
+
|
|
66
|
+
it('export users collection in csv', async () => {
|
|
67
|
+
const response = await importExportService.create({
|
|
68
|
+
method: 'export',
|
|
69
|
+
servicePath: 'api/users',
|
|
70
|
+
transform: {
|
|
71
|
+
omit: ['_id']
|
|
72
|
+
},
|
|
73
|
+
format: 'csv'
|
|
74
|
+
})
|
|
75
|
+
expect(response.SignedUrl).toExist()
|
|
76
|
+
await storageService.remove('import-export/' + response.id)
|
|
77
|
+
})
|
|
78
|
+
.timeout(30000)
|
|
79
|
+
|
|
80
|
+
// Cleanup
|
|
81
|
+
after(async () => {
|
|
82
|
+
if (server) await server.close()
|
|
83
|
+
await app.db.instance.dropDatabase()
|
|
84
|
+
await app.db.disconnect()
|
|
85
|
+
})
|
|
86
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
2
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
3
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
4
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
5
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
6
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
7
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
8
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
9
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
10
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
11
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
12
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
13
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
14
|
+
{"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import chai from 'chai'
|
|
2
|
+
import chailint from 'chai-lint'
|
|
3
|
+
import _ from 'lodash'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import fs from 'fs-extra'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
import core, { kdk, hooks, permissions } from '../../../core/api/index.js'
|
|
8
|
+
import map, {
|
|
9
|
+
permissions as mapPermissions, createCatalogService, createProjectsService
|
|
10
|
+
} from '../../../map/api/index.js'
|
|
11
|
+
|
|
12
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
const { util, expect } = chai
|
|
14
|
+
|
|
15
|
+
describe('map:catalog', () => {
|
|
16
|
+
let app, server, port, // baseUrl,
|
|
17
|
+
userService, userObject, catalogService, defaultLayers,
|
|
18
|
+
zonesLayer, vigicruesLayer, contextObject, projectService, projectObject
|
|
19
|
+
|
|
20
|
+
before(() => {
|
|
21
|
+
chailint(chai, util)
|
|
22
|
+
|
|
23
|
+
// Register all default hooks for authorisation
|
|
24
|
+
// Default rules for all users
|
|
25
|
+
permissions.defineAbilities.registerHook(permissions.defineUserAbilities)
|
|
26
|
+
// Then rules for maps
|
|
27
|
+
permissions.defineAbilities.registerHook(mapPermissions.defineUserAbilities)
|
|
28
|
+
|
|
29
|
+
app = kdk()
|
|
30
|
+
// Register authorisation/log hook
|
|
31
|
+
app.hooks({
|
|
32
|
+
before: { all: [hooks.authorise] },
|
|
33
|
+
error: { all: hooks.log }
|
|
34
|
+
})
|
|
35
|
+
port = app.get('port')
|
|
36
|
+
// baseUrl = `http://localhost:${port}${app.get('apiPath')}`
|
|
37
|
+
return app.db.connect()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('registers the services', async () => {
|
|
41
|
+
await app.configure(core)
|
|
42
|
+
userService = app.getService('users')
|
|
43
|
+
expect(userService).toExist()
|
|
44
|
+
await app.configure(map)
|
|
45
|
+
// Create a global catalog/project service
|
|
46
|
+
await createCatalogService.call(app)
|
|
47
|
+
catalogService = app.getService('catalog')
|
|
48
|
+
expect(catalogService).toExist()
|
|
49
|
+
await createProjectsService.call(app)
|
|
50
|
+
projectService = app.getService('projects')
|
|
51
|
+
expect(projectService).toExist()
|
|
52
|
+
// Now app is configured launch the server
|
|
53
|
+
server = await app.listen(port)
|
|
54
|
+
await new Promise(resolve => server.once('listening', () => resolve()))
|
|
55
|
+
})
|
|
56
|
+
// Let enough time to process
|
|
57
|
+
.timeout(5000)
|
|
58
|
+
|
|
59
|
+
it('creates a test user', async () => {
|
|
60
|
+
userObject = await userService.create({ email: 'test-user@test.org', name: 'test-user' }, { checkAuthorisation: true })
|
|
61
|
+
const users = await userService.find({ query: { 'profile.name': 'test-user' }, user: userObject, checkAuthorisation: true })
|
|
62
|
+
expect(users.data.length > 0).beTrue()
|
|
63
|
+
})
|
|
64
|
+
// Let enough time to process
|
|
65
|
+
.timeout(5000)
|
|
66
|
+
|
|
67
|
+
it('registers the default layer catalog', async () => {
|
|
68
|
+
const layers = await fs.readJson(path.join(__dirname, 'config/layers.json'))
|
|
69
|
+
expect(layers.length > 0)
|
|
70
|
+
// Create a global catalog service
|
|
71
|
+
defaultLayers = await catalogService.create(layers)
|
|
72
|
+
expect(defaultLayers.length > 0)
|
|
73
|
+
zonesLayer = _.find(defaultLayers, { name: 'zones' })
|
|
74
|
+
vigicruesLayer = _.find(defaultLayers, { name: 'vigicrues-stations' })
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('manages layers, contexts and categories', async () => {
|
|
78
|
+
const layer = await catalogService.create({ name: 'dummy', type: 'OverlayLayer' })
|
|
79
|
+
// Can't duplicate name
|
|
80
|
+
let doublonLayer
|
|
81
|
+
try {
|
|
82
|
+
doublonLayer = await catalogService.create({ name: 'dummy', type: 'OverlayLayer' })
|
|
83
|
+
} catch (error) {
|
|
84
|
+
expect(error).toExist()
|
|
85
|
+
expect(error.name).to.equal('Conflict')
|
|
86
|
+
expect(error.data.translation.key).to.equal('OBJECT_ID_ALREADY_TAKEN')
|
|
87
|
+
}
|
|
88
|
+
expect(doublonLayer).beUndefined()
|
|
89
|
+
// Can duplicate if we target different types
|
|
90
|
+
let context = await catalogService.create({ name: 'dummy', type: 'Context', layers: ['dummy'] })
|
|
91
|
+
let category = await catalogService.create({ name: 'dummy', type: 'Category', layers: ['dummy'] })
|
|
92
|
+
// Check for context/category filtering by default
|
|
93
|
+
const response = await catalogService.find({ query: {}, paginate: false })
|
|
94
|
+
expect(response.length === defaultLayers.length + 1)
|
|
95
|
+
// Check for automated context/category update whn layer is renamed/removed
|
|
96
|
+
await catalogService.patch(layer._id.toString(), { name: 'oldDummy' })
|
|
97
|
+
context = await catalogService.get(context._id.toString())
|
|
98
|
+
expect(context.layers).to.deep.equal(['oldDummy'])
|
|
99
|
+
category = await catalogService.get(category._id.toString())
|
|
100
|
+
expect(category.layers).to.deep.equal(['oldDummy'])
|
|
101
|
+
await catalogService.remove(layer._id.toString())
|
|
102
|
+
context = await catalogService.get(context._id.toString())
|
|
103
|
+
expect(context.layers).to.deep.equal([])
|
|
104
|
+
await catalogService.remove(context._id.toString())
|
|
105
|
+
category = await catalogService.get(category._id.toString())
|
|
106
|
+
expect(category.layers).to.deep.equal([])
|
|
107
|
+
await catalogService.remove(category._id.toString())
|
|
108
|
+
})
|
|
109
|
+
// Let enough time to process
|
|
110
|
+
.timeout(5000)
|
|
111
|
+
|
|
112
|
+
it('creates a context', async () => {
|
|
113
|
+
contextObject = await catalogService.create({ name: 'context', type: 'Context', layers: ['vigicrues-stations', 'zones'] })
|
|
114
|
+
// Rename layer and check it has been updated in context
|
|
115
|
+
zonesLayer = await catalogService.patch(zonesLayer._id, { name: 'new-zones' })
|
|
116
|
+
contextObject = await catalogService.get(contextObject._id)
|
|
117
|
+
expect(contextObject.layers).to.deep.equal(['vigicrues-stations', 'new-zones'])
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('creates a project', async () => {
|
|
121
|
+
projectObject = await projectService.create({
|
|
122
|
+
name: 'project', views: [{ _id: contextObject._id }], layers: [{ _id: zonesLayer._id }, { name: vigicruesLayer.name }]
|
|
123
|
+
})
|
|
124
|
+
// Remove context and check it has been updated in project
|
|
125
|
+
await catalogService.remove(contextObject._id)
|
|
126
|
+
projectObject = await projectService.get(projectObject._id)
|
|
127
|
+
expect(projectObject.views).to.deep.equal([])
|
|
128
|
+
// Remove layer and check it has been updated in project
|
|
129
|
+
await catalogService.remove(zonesLayer._id)
|
|
130
|
+
projectObject = await projectService.get(projectObject._id, { query: { populate: true } })
|
|
131
|
+
expect(projectObject.layers).to.deep.equal([{
|
|
132
|
+
_id: vigicruesLayer._id,
|
|
133
|
+
name: vigicruesLayer.name,
|
|
134
|
+
service: vigicruesLayer.name
|
|
135
|
+
}])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
it('clears the catalog and projects', async () => {
|
|
139
|
+
await catalogService.remove(null, { query: { } })
|
|
140
|
+
const layers = await catalogService.find({ query: {}, paginate: false })
|
|
141
|
+
expect(layers.length === 0)
|
|
142
|
+
await projectService.remove(projectObject._id)
|
|
143
|
+
const projects = await projectService.find({ query: {}, paginate: false })
|
|
144
|
+
expect(projects.length === 0)
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
it('removes the test user', async () => {
|
|
148
|
+
await userService.remove(userObject._id, {
|
|
149
|
+
user: userObject,
|
|
150
|
+
checkAuthorisation: true
|
|
151
|
+
})
|
|
152
|
+
const users = await userService.find({ query: { name: 'test-user' } })
|
|
153
|
+
expect(users.data.length === 0).beTrue()
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// Cleanup
|
|
157
|
+
after(async () => {
|
|
158
|
+
if (server) await server.close()
|
|
159
|
+
await catalogService.Model.drop()
|
|
160
|
+
await projectService.Model.drop()
|
|
161
|
+
await userService.Model.drop()
|
|
162
|
+
await app.db.disconnect()
|
|
163
|
+
})
|
|
164
|
+
})
|
|
@@ -16,9 +16,9 @@ const { util, expect } = chai
|
|
|
16
16
|
|
|
17
17
|
describe('map:services', () => {
|
|
18
18
|
let app, server, port, // baseUrl,
|
|
19
|
-
userService, userObject,
|
|
20
|
-
zonesService, vigicruesStationsService,
|
|
21
|
-
|
|
19
|
+
userService, userObject, catalogService, defaultLayers,
|
|
20
|
+
zonesService, vigicruesStationsService, nbStations, vigicruesObsService,
|
|
21
|
+
adsbObsService, items, eventListeners, eventCount, eventData
|
|
22
22
|
|
|
23
23
|
function eventsOn (service) {
|
|
24
24
|
eventListeners = {}
|
|
@@ -81,8 +81,6 @@ describe('map:services', () => {
|
|
|
81
81
|
userService = app.getService('users')
|
|
82
82
|
expect(userService).toExist()
|
|
83
83
|
await app.configure(map)
|
|
84
|
-
geocoderService = app.getService('geocoder')
|
|
85
|
-
expect(geocoderService).toExist()
|
|
86
84
|
// Create a global catalog service
|
|
87
85
|
await createCatalogService.call(app)
|
|
88
86
|
catalogService = app.getService('catalog')
|
|
@@ -110,41 +108,6 @@ describe('map:services', () => {
|
|
|
110
108
|
expect(defaultLayers.length > 0)
|
|
111
109
|
})
|
|
112
110
|
|
|
113
|
-
it('manages layers, contexts and categories', async () => {
|
|
114
|
-
const layer = await catalogService.create({ name: 'dummy', type: 'OverlayLayer' })
|
|
115
|
-
// Can't duplicate name
|
|
116
|
-
let doublonLayer
|
|
117
|
-
try {
|
|
118
|
-
doublonLayer = await catalogService.create({ name: 'dummy', type: 'OverlayLayer' })
|
|
119
|
-
} catch (error) {
|
|
120
|
-
expect(error).toExist()
|
|
121
|
-
expect(error.name).to.equal('Conflict')
|
|
122
|
-
expect(error.data.translation.key).to.equal('OBJECT_ID_ALREADY_TAKEN')
|
|
123
|
-
}
|
|
124
|
-
expect(doublonLayer).beUndefined()
|
|
125
|
-
// Can duplicate if we target different types
|
|
126
|
-
let context = await catalogService.create({ name: 'dummy', type: 'Context', layers: ['dummy'] })
|
|
127
|
-
let category = await catalogService.create({ name: 'dummy', type: 'Category', layers: ['dummy'] })
|
|
128
|
-
// Check for context/category filtering by default
|
|
129
|
-
const response = await catalogService.find({ query: {}, paginate: false })
|
|
130
|
-
expect(response.length === defaultLayers.length + 1)
|
|
131
|
-
// Check for automated context/category update whn layer is renamed/removed
|
|
132
|
-
await catalogService.patch(layer._id.toString(), { name: 'oldDummy' })
|
|
133
|
-
context = await catalogService.get(context._id.toString())
|
|
134
|
-
expect(context.layers).to.deep.equal(['oldDummy'])
|
|
135
|
-
category = await catalogService.get(category._id.toString())
|
|
136
|
-
expect(category.layers).to.deep.equal(['oldDummy'])
|
|
137
|
-
await catalogService.remove(layer._id.toString())
|
|
138
|
-
context = await catalogService.get(context._id.toString())
|
|
139
|
-
expect(context.layers).to.deep.equal([])
|
|
140
|
-
await catalogService.remove(context._id.toString())
|
|
141
|
-
category = await catalogService.get(category._id.toString())
|
|
142
|
-
expect(category.layers).to.deep.equal([])
|
|
143
|
-
await catalogService.remove(category._id.toString())
|
|
144
|
-
})
|
|
145
|
-
// Let enough time to process
|
|
146
|
-
.timeout(5000)
|
|
147
|
-
|
|
148
111
|
it('create and feed the zones service', async () => {
|
|
149
112
|
// Create the service
|
|
150
113
|
const zonesLayer = _.find(defaultLayers, { name: 'zones' })
|
|
@@ -217,6 +180,7 @@ describe('map:services', () => {
|
|
|
217
180
|
expect(vigicruesStationsService).toExist()
|
|
218
181
|
// Feed the collection
|
|
219
182
|
const stations = fs.readJsonSync(path.join(__dirname, 'data/vigicrues.stations.json')).features
|
|
183
|
+
nbStations = stations.length
|
|
220
184
|
await vigicruesStationsService.create(stations)
|
|
221
185
|
})
|
|
222
186
|
// Let enough time to process
|
|
@@ -315,7 +279,27 @@ describe('map:services', () => {
|
|
|
315
279
|
.timeout(5000)
|
|
316
280
|
|
|
317
281
|
it('performs spatial filtering on vigicrues stations service', async () => {
|
|
318
|
-
|
|
282
|
+
let result = await vigicruesStationsService.find({
|
|
283
|
+
query: { south: -90, north: 90, east: 180, west: -180 },
|
|
284
|
+
paginate: false
|
|
285
|
+
})
|
|
286
|
+
expect(result.features.length).to.equal(nbStations)
|
|
287
|
+
result = await vigicruesStationsService.find({
|
|
288
|
+
query: { south: 80, north: 85, east: 180, west: -180 },
|
|
289
|
+
paginate: false
|
|
290
|
+
})
|
|
291
|
+
expect(result.features.length).to.equal(0)
|
|
292
|
+
result = await vigicruesStationsService.find({
|
|
293
|
+
query: { south: -85, north: -80, east: 180, west: -180 },
|
|
294
|
+
paginate: false
|
|
295
|
+
})
|
|
296
|
+
expect(result.features.length).to.equal(0)
|
|
297
|
+
result = await vigicruesStationsService.find({
|
|
298
|
+
query: { south: -20, north: 20, east: 100, west: -100 },
|
|
299
|
+
paginate: false
|
|
300
|
+
})
|
|
301
|
+
expect(result.features.length).to.equal(0)
|
|
302
|
+
result = await vigicruesStationsService.find({
|
|
319
303
|
query: {
|
|
320
304
|
geometry: {
|
|
321
305
|
$near: {
|
|
@@ -512,26 +496,6 @@ describe('map:services', () => {
|
|
|
512
496
|
// Let enough time to process
|
|
513
497
|
.timeout(10000)
|
|
514
498
|
|
|
515
|
-
it('geocode an address', async () => {
|
|
516
|
-
const address = '80 chemin des tournesols, 11400 Castelnaudary'
|
|
517
|
-
const response = await geocoderService.create({ address: address }, { user: userObject, checkAuthorisation: true })
|
|
518
|
-
expect(response.length === 1).beTrue()
|
|
519
|
-
position = response[0]
|
|
520
|
-
expect(position.latitude).toExist()
|
|
521
|
-
expect(position.longitude).toExist()
|
|
522
|
-
})
|
|
523
|
-
// Let enough time to process
|
|
524
|
-
.timeout(10000)
|
|
525
|
-
|
|
526
|
-
it('reverse geocode a position', async () => {
|
|
527
|
-
const response = await geocoderService.create(position, { user: userObject, checkAuthorisation: true })
|
|
528
|
-
expect(response.length > 0).beTrue()
|
|
529
|
-
expect(response[0].country).toExist()
|
|
530
|
-
expect(response[0].streetName).toExist()
|
|
531
|
-
})
|
|
532
|
-
// Let enough time to process
|
|
533
|
-
.timeout(10000)
|
|
534
|
-
|
|
535
499
|
it('clears the layers', async () => {
|
|
536
500
|
for (let i = 0; i < defaultLayers.length; ++i) {
|
|
537
501
|
await catalogService.remove(defaultLayers[i]._id)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"level":"error","message":"error: api/catalog - Method: create: Object with name equals to dummy already exist for service catalog"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{"level":"info","message":"Logger configured"}
|
|
2
|
+
{"level":"info","message":"Initializing weacast-gfs plugin"}
|
|
3
|
+
{"level":"info","message":"Initializing gfs-world forecast"}
|
|
4
|
+
{"level":"info","message":"Checking for up-to-date forecast data on gfs-world/u-wind"}
|
|
5
|
+
{"level":"info","message":"Checking for up-to-date forecast data on gfs-world/v-wind"}
|
|
6
|
+
{"level":"info","message":"Completed forecast data update on gfs-world/u-wind"}
|
|
7
|
+
{"level":"info","message":"Completed forecast data update on gfs-world/v-wind"}
|
|
8
|
+
{"level":"error","message":"Cannot check alert 65b23e9b0c441d5b46ac6f77 as target probes service is not available"}
|
|
9
|
+
{"level":"error","message":"error: api/alerts - Method: create: Not Found"}
|
|
10
|
+
{"level":"error","message":"Cannot check alert 65b23e9b0c441d5b46ac6f78 as target probes service is not available"}
|
|
11
|
+
{"level":"error","message":"error: api/alerts - Method: create: Not Found"}
|
|
12
|
+
{"level":"error","message":"Cannot check alert 65b23e9b0c441d5b46ac6f79 as target probes service is not available"}
|
|
13
|
+
{"level":"error","message":"error: api/alerts - Method: create: Not Found"}
|
|
14
|
+
{"level":"error","message":"error: api/alerts - Method: create: Not Found"}
|
|
15
|
+
{"level":"error","message":"error: api/alerts - Method: create: Not Found"}
|
|
16
|
+
{"level":"error","message":"Cannot check alert 65b23e9b0c441d5b46ac74bc as no data is available for features service vigicrues-observations"}
|
|
17
|
+
{"level":"error","message":"error: api/alerts - Method: create: Not Found"}
|
|
18
|
+
{"level":"error","message":"error: api/catalog - Method: create: Object with name equals to dummy already exist for service catalog"}
|
|
19
|
+
{"level":"info","message":"Logger configured"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import makeDebug from 'debug'
|
|
2
|
-
import { click, clickAction, isElementVisible } from './utils.js'
|
|
2
|
+
import { countElements, click, clickAction, isElementVisible, isActionVisible } from './utils.js'
|
|
3
3
|
|
|
4
4
|
const debug = makeDebug('kdk:core:test:layout')
|
|
5
5
|
|
|
@@ -79,26 +79,46 @@ export async function isWindowMaximized (page, placement) {
|
|
|
79
79
|
return isElementVisible(page, `#restore-${placement}-window`)
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
async function clickWindowControl (page, placement, control) {
|
|
83
|
+
const action = `${control}-${placement}-window`
|
|
84
|
+
if (!await isActionVisible(page, action)) await clickAction(page, 'window-controls')
|
|
85
|
+
await clickAction(page, action)
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
export async function closeWindow (page, placement) {
|
|
83
|
-
await
|
|
89
|
+
await clickWindowControl(page, placement, 'close')
|
|
84
90
|
}
|
|
85
91
|
|
|
86
92
|
export async function maximizeWindow (page, placement) {
|
|
87
|
-
await
|
|
93
|
+
await clickWindowControl(page, placement, 'maximize')
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
export async function restoreWindow (page, placement) {
|
|
91
|
-
await
|
|
97
|
+
await clickWindowControl(page, placement, 'restore')
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
export async function pinWindow (page, placement) {
|
|
95
|
-
await
|
|
101
|
+
await clickWindowControl(page, placement, 'pin')
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function unpinWindow (page, placement) {
|
|
105
|
+
await clickWindowControl(page, placement, 'unpin')
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
export async function clickFab (page) {
|
|
99
109
|
return clickAction(page, 'fab')
|
|
100
110
|
}
|
|
101
111
|
|
|
112
|
+
export async function clickFabAction (page, action) {
|
|
113
|
+
await clickAction(page, 'fab')
|
|
114
|
+
return clickAction(page, action)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function countFabActions (page) {
|
|
118
|
+
return countElements(page, '//a[contains(@class, "k-action-fab-action")]')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
102
122
|
export async function closeWelcomeDialog (page) {
|
|
103
123
|
await click(page, '.q-dialog #close-button')
|
|
104
124
|
}
|
|
@@ -52,6 +52,13 @@ export async function click (page, selector, wait = 500) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/* Helper function to check whether an action is visible
|
|
56
|
+
*/
|
|
57
|
+
export async function isActionVisible (page, action) {
|
|
58
|
+
const selector = `#${action}`
|
|
59
|
+
return isElementVisible(page, selector)
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
/* Helper function to click on an action selector
|
|
56
63
|
*/
|
|
57
64
|
export async function clickAction (page, action, wait = 500) {
|
|
@@ -29,6 +29,14 @@ export async function clickLayerCategory (page, tabId, categoryId, wait = 500) {
|
|
|
29
29
|
await core.clickPaneAction(page, 'right', categoryId, wait)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export async function layerExists (page, tabId, layer) {
|
|
33
|
+
const isCatalogOpened = await clickCatalogTab(page, tabId)
|
|
34
|
+
const layerId = getLayerId(layer)
|
|
35
|
+
const exists = await core.elementExists(page, `#${layerId}`)
|
|
36
|
+
if (!isCatalogOpened) await core.clickOpener(page, 'right')
|
|
37
|
+
return exists
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
export async function clickLayer (page, tabId, layer, wait = 1000) {
|
|
33
41
|
const isCatalogOpened = await clickCatalogTab(page, tabId)
|
|
34
42
|
const layerId = getLayerId(layer)
|
|
@@ -39,7 +47,7 @@ export async function clickLayer (page, tabId, layer, wait = 1000) {
|
|
|
39
47
|
if (!isCategoryOpened) await core.clickPaneAction(page, 'right', categoryId, 1000)
|
|
40
48
|
}
|
|
41
49
|
let selector = `#${layerId} .q-toggle`
|
|
42
|
-
// some layers have a toggle (
|
|
50
|
+
// some layers have a toggle (regular layers), some don't (base layers)
|
|
43
51
|
if (!await core.elementExists(page, selector)) {
|
|
44
52
|
selector = `#${layerId}`
|
|
45
53
|
}
|
|
@@ -111,6 +119,7 @@ export async function dropFile (page, filePath, wait = 2000) {
|
|
|
111
119
|
const loaderSelector = '#dropFileInput'
|
|
112
120
|
const loader = await page.$(loaderSelector)
|
|
113
121
|
await loader.uploadFile(filePath)
|
|
122
|
+
await page.waitForNetworkIdle()
|
|
114
123
|
await page.waitForTimeout(wait)
|
|
115
124
|
}
|
|
116
125
|
|
|
@@ -126,6 +135,12 @@ export async function addView (page) {
|
|
|
126
135
|
await page.waitForTimeout(1000)
|
|
127
136
|
}
|
|
128
137
|
|
|
138
|
+
export async function addProject (page) {
|
|
139
|
+
await core.clickFab(page)
|
|
140
|
+
await core.clickAction(page, 'create-project')
|
|
141
|
+
await page.waitForTimeout(1000)
|
|
142
|
+
}
|
|
143
|
+
|
|
129
144
|
export async function importLayer (page, filePath, featureId = undefined, wait = 2000) {
|
|
130
145
|
await addLayer(page)
|
|
131
146
|
await core.uploadFile(page, '#file-field', filePath)
|
|
@@ -189,5 +204,67 @@ export async function removeView (page, tabId, name) {
|
|
|
189
204
|
const isCatalogOpened = await clickCatalogTab(page, tabId, 2000)
|
|
190
205
|
await core.clickItemAction(page, 'catalog/KViewSelector', name, 'view-overflowmenu', 1000)
|
|
191
206
|
await core.clickAction(page, 'remove-view', 1000)
|
|
207
|
+
await core.click(page, '.q-dialog button:nth-child(2)', 1000)
|
|
208
|
+
if (!isCatalogOpened) await core.clickOpener(page, 'right')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export async function createProject (page, name, options, wait = 2000) {
|
|
212
|
+
const { categories, layers, views } = options
|
|
213
|
+
await addProject(page)
|
|
214
|
+
await core.type(page, '#name-field', name)
|
|
215
|
+
await core.type(page, '#description-field', `${name} description`)
|
|
216
|
+
// Open categories first
|
|
217
|
+
for (let i = 0; i < categories.length; i++) {
|
|
218
|
+
const category = categories[i]
|
|
219
|
+
await core.clickXPath(page, `//div[contains(text(), "${category}")]`)
|
|
220
|
+
}
|
|
221
|
+
// Then select layers
|
|
222
|
+
for (let i = 0; i < layers.length; i++) {
|
|
223
|
+
const layer = layers[i]
|
|
224
|
+
await core.clickXPath(page, `//div[contains(text(), "${layer}")]/../../preceding-sibling::div[contains(@class, "q-checkbox")]`)
|
|
225
|
+
}
|
|
226
|
+
if (views) {
|
|
227
|
+
for (let i = 0; i < views.length; i++) {
|
|
228
|
+
const view = views[i]
|
|
229
|
+
await core.clickXPath(page, `//div[contains(text(), "${view}")]/../../preceding-sibling::div[contains(@class, "q-checkbox")]`)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
await core.clickAction(page, 'apply-button', 1000)
|
|
233
|
+
await page.waitForTimeout(wait)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export async function projectExists (page, tabId, name) {
|
|
237
|
+
const isCatalogOpened = await clickCatalogTab(page, tabId, 2000)
|
|
238
|
+
const exists = await core.itemExists(page, 'catalog/KProjectSelector', name)
|
|
239
|
+
if (!isCatalogOpened) await core.clickOpener(page, 'right')
|
|
240
|
+
return exists
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export async function clickProject (page, tabId, name) {
|
|
244
|
+
const isCatalogOpened = await clickCatalogTab(page, tabId, 2000)
|
|
245
|
+
await core.clickItem(page, 'catalog/KProjectSelector', name)
|
|
246
|
+
// Switching to project automatically closes the catalog tab
|
|
247
|
+
if (isCatalogOpened) await core.clickOpener(page, 'right')
|
|
248
|
+
await page.waitForNetworkIdle()
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export async function switchProject (page, name, wait = 2000) {
|
|
252
|
+
await core.click(page, '#project-menu', 2000)
|
|
253
|
+
await core.clickXPath(page, `//div[contains(@component, "collection/KItem") and contains(., "${name}")]`, 1000)
|
|
254
|
+
await page.waitForNetworkIdle()
|
|
255
|
+
await page.waitForTimeout(wait)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export async function closeProject (page, wait = 2000) {
|
|
259
|
+
await core.click(page, '#close-project')
|
|
260
|
+
await page.waitForNetworkIdle()
|
|
261
|
+
await page.waitForTimeout(wait)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export async function removeProject (page, tabId, name) {
|
|
265
|
+
const isCatalogOpened = await clickCatalogTab(page, tabId, 2000)
|
|
266
|
+
await core.clickItemAction(page, 'catalog/KProjectSelector', name, 'project-overflowmenu', 1000)
|
|
267
|
+
await core.clickAction(page, 'remove-project', 1000)
|
|
268
|
+
await core.click(page, '.q-dialog button:nth-child(2)', 1000)
|
|
192
269
|
if (!isCatalogOpened) await core.clickOpener(page, 'right')
|
|
193
270
|
}
|
package/test/client/map/time.js
CHANGED
|
@@ -11,7 +11,8 @@ export async function openTimeline (page) {
|
|
|
11
11
|
|
|
12
12
|
export async function clickTimelineHour (page, hour, wait = 1000) {
|
|
13
13
|
const isTimelineOpened = await openTimeline(page)
|
|
14
|
-
|
|
14
|
+
await core.click(page, '#time-button', wait)
|
|
15
|
+
const xpath = `//div[contains(@class, "q-time__clock-pos-${hour}")]`
|
|
15
16
|
const elements = await page.$x(xpath)
|
|
16
17
|
if (elements.length > 0) {
|
|
17
18
|
elements[0].click()
|