chore: port DataLayer.js tests to PW
This commit is contained in:
parent
6a1fb44085
commit
490a1a6e19
7 changed files with 338 additions and 465 deletions
|
@ -1,463 +0,0 @@
|
||||||
describe('U.DataLayer', () => {
|
|
||||||
let path = '/map/99/datalayer/update/62/',
|
|
||||||
map,
|
|
||||||
datalayer
|
|
||||||
|
|
||||||
before(async () => {
|
|
||||||
fetchMock.mock(/\/datalayer\/62\/\?.*/, JSON.stringify(RESPONSES.datalayer62_GET))
|
|
||||||
fetchMock.sticky('/map/99/update/settings/', { id: 99 })
|
|
||||||
this.options = {
|
|
||||||
umap_id: 99,
|
|
||||||
}
|
|
||||||
MAP = map = initMap({ umap_id: 99 })
|
|
||||||
const datalayer_options = defaultDatalayerData()
|
|
||||||
await map.initDataLayers([datalayer_options])
|
|
||||||
datalayer = map.getDataLayerByUmapId(62)
|
|
||||||
enableEdit()
|
|
||||||
})
|
|
||||||
after(() => {
|
|
||||||
fetchMock.restore()
|
|
||||||
resetMap()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#init()', () => {
|
|
||||||
it('should be added in datalayers index', () => {
|
|
||||||
assert.notEqual(map.datalayers_index.indexOf(datalayer), -1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#edit()', () => {
|
|
||||||
var editButton, form, input, forceButton
|
|
||||||
|
|
||||||
it('row in control should be active', () => {
|
|
||||||
assert.notOk(
|
|
||||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(datalayer) + '.off')
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have edit button', () => {
|
|
||||||
editButton = qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit')
|
|
||||||
assert.ok(editButton)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have toggle visibility element', () => {
|
|
||||||
assert.ok(qs('.leaflet-control-browse i.layer-toggle'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should exist only one datalayer', () => {
|
|
||||||
assert.equal(qsa('.leaflet-control-browse i.layer-toggle').length, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should build a form on edit button click', () => {
|
|
||||||
happen.click(editButton)
|
|
||||||
form = qs('form.umap-form')
|
|
||||||
input = qs('form.umap-form input[name="name"]')
|
|
||||||
assert.ok(form)
|
|
||||||
assert.ok(input)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should update name on input change', () => {
|
|
||||||
var new_name = 'This is a new name'
|
|
||||||
input.value = new_name
|
|
||||||
happen.once(input, { type: 'input' })
|
|
||||||
assert.equal(datalayer.options.name, new_name)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have made datalayer dirty', () => {
|
|
||||||
assert.ok(datalayer.isDirty)
|
|
||||||
assert.notEqual(map.dirty_datalayers.indexOf(datalayer), -1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have made Map dirty', () => {
|
|
||||||
assert.ok(map.isDirty)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call datalayer.save on save button click', (done) => {
|
|
||||||
const postDatalayer = fetchMock.post(path, () => {
|
|
||||||
return defaultDatalayerData()
|
|
||||||
})
|
|
||||||
clickSave()
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert(fetchMock.called(path))
|
|
||||||
done()
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show alert if server respond 412', (done) => {
|
|
||||||
cleanAlert()
|
|
||||||
fetchMock.restore()
|
|
||||||
fetchMock.post(path, 412)
|
|
||||||
happen.click(editButton)
|
|
||||||
input = qs('form.umap-form input[name="name"]')
|
|
||||||
input.value = 'a new name'
|
|
||||||
happen.once(input, { type: 'input' })
|
|
||||||
clickSave()
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert(L.DomUtil.hasClass(map._container, 'umap-alert'))
|
|
||||||
assert.notEqual(map.dirty_datalayers.indexOf(datalayer), -1)
|
|
||||||
const forceButton = qs('#umap-alert-container .umap-action')
|
|
||||||
assert.ok(forceButton)
|
|
||||||
done()
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should save anyway on force save button click', (done) => {
|
|
||||||
const forceButton = qs('#umap-alert-container .umap-action')
|
|
||||||
fetchMock.restore()
|
|
||||||
fetchMock.post(path, defaultDatalayerData)
|
|
||||||
happen.click(forceButton)
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert.notOk(qs('#umap-alert-container .umap-action'))
|
|
||||||
assert(fetchMock.called(path))
|
|
||||||
assert.equal(map.dirty_datalayers.indexOf(datalayer), -1)
|
|
||||||
done()
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#save() new', () => {
|
|
||||||
let newLayerButton, form, input, newDatalayer, editButton, manageButton
|
|
||||||
|
|
||||||
it('should have a manage datalayers action', () => {
|
|
||||||
enableEdit()
|
|
||||||
manageButton = qs('.manage-datalayers')
|
|
||||||
assert.ok(manageButton)
|
|
||||||
happen.click(manageButton)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have a new layer button', () => {
|
|
||||||
newLayerButton = qs('#umap-ui-container .add-datalayer')
|
|
||||||
assert.ok(newLayerButton)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should build a form on new layer button click', () => {
|
|
||||||
happen.click(newLayerButton)
|
|
||||||
form = qs('form.umap-form')
|
|
||||||
input = qs('form.umap-form input[name="name"]')
|
|
||||||
assert.ok(form)
|
|
||||||
assert.ok(input)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have an empty name', () => {
|
|
||||||
assert.notOk(input.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have created a new datalayer', () => {
|
|
||||||
assert.equal(map.datalayers_index.length, 2)
|
|
||||||
newDatalayer = map.datalayers_index[1]
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have made Map dirty', () => {
|
|
||||||
assert.ok(map.isDirty)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should update name on input change', () => {
|
|
||||||
var new_name = 'This is a new name'
|
|
||||||
input.value = new_name
|
|
||||||
happen.once(input, { type: 'input' })
|
|
||||||
assert.equal(newDatalayer.options.name, new_name)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should set umap_id on save callback', async () => {
|
|
||||||
assert.notOk(newDatalayer.umap_id)
|
|
||||||
fetchMock.post('/map/99/datalayer/create/', defaultDatalayerData({ id: 63 }))
|
|
||||||
clickSave()
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert.equal(newDatalayer.umap_id, 63)
|
|
||||||
resolve()
|
|
||||||
}, 1000)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have unset map dirty', () => {
|
|
||||||
assert.notOk(map.isDirty)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have edit button', () => {
|
|
||||||
editButton = qs('#browse_data_toggle_' + L.stamp(newDatalayer) + ' .layer-edit')
|
|
||||||
assert.ok(editButton)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should call update if we edit again', async () => {
|
|
||||||
happen.click(editButton)
|
|
||||||
assert.notOk(map.isDirty)
|
|
||||||
input = qs('form.umap-form input[name="name"]')
|
|
||||||
input.value = "a new name again but we don't care which"
|
|
||||||
happen.once(input, { type: 'input' })
|
|
||||||
assert.ok(map.isDirty)
|
|
||||||
var response = () => {
|
|
||||||
return defaultDatalayerData({ pk: 63 })
|
|
||||||
}
|
|
||||||
var spy = sinon.spy(response)
|
|
||||||
fetchMock.post('/map/99/datalayer/update/63/', spy)
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
clickSave()
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert.ok(spy.calledOnce)
|
|
||||||
resolve()
|
|
||||||
}, 1000)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#iconClassChange()', () => {
|
|
||||||
it('should change icon class', () => {
|
|
||||||
happen.click(qs('[data-id="' + datalayer._leaflet_id + '"] .layer-edit'))
|
|
||||||
changeSelectValue(
|
|
||||||
qs('form#datalayer-advanced-properties select[name=iconClass]'),
|
|
||||||
'Circle'
|
|
||||||
)
|
|
||||||
assert.notOk(qs('div.umap-div-icon'))
|
|
||||||
assert.ok(qs('div.umap-circle-icon'))
|
|
||||||
happen.click(
|
|
||||||
qs('form#datalayer-advanced-properties .umap-field-iconClass .undefine')
|
|
||||||
)
|
|
||||||
assert.notOk(qs('div.umap-circle-icon'))
|
|
||||||
assert.ok(qs('div.umap-div-icon'))
|
|
||||||
clickCancel()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#show/hide', () => {
|
|
||||||
it('should hide features on hide', () => {
|
|
||||||
assert.ok(qs('div.umap-div-icon'))
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
datalayer.hide()
|
|
||||||
assert.notOk(qs('div.umap-div-icon'))
|
|
||||||
assert.notOk(qs('path[fill="none"]'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should show features on show', () => {
|
|
||||||
assert.notOk(qs('div.umap-div-icon'))
|
|
||||||
assert.notOk(qs('path[fill="none"]'))
|
|
||||||
datalayer.show()
|
|
||||||
assert.ok(qs('div.umap-div-icon'))
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#clone()', () => {
|
|
||||||
it('should clone everything but the id and the name', () => {
|
|
||||||
enableEdit()
|
|
||||||
var clone = datalayer.clone()
|
|
||||||
assert.notOk(clone.umap_id)
|
|
||||||
assert.notEqual(clone.options.name, datalayer.name)
|
|
||||||
assert.ok(clone.options.name)
|
|
||||||
assert.equal(clone.options.color, datalayer.options.color)
|
|
||||||
assert.equal(clone.options.stroke, datalayer.options.stroke)
|
|
||||||
clone._delete()
|
|
||||||
clickSave()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#restore()', () => {
|
|
||||||
var oldConfirm,
|
|
||||||
newConfirm = () => {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
oldConfirm = window.confirm
|
|
||||||
window.confirm = newConfirm
|
|
||||||
})
|
|
||||||
after(() => {
|
|
||||||
window.confirm = oldConfirm
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should restore everything', (done) => {
|
|
||||||
enableEdit()
|
|
||||||
var geojson = L.Util.CopyJSON(RESPONSES.datalayer62_GET)
|
|
||||||
geojson.features.push({
|
|
||||||
geometry: {
|
|
||||||
type: 'Point',
|
|
||||||
coordinates: [-1.274658203125, 50.57634993749885],
|
|
||||||
},
|
|
||||||
type: 'Feature',
|
|
||||||
id: 1807,
|
|
||||||
properties: { _umap_options: {}, name: 'new point from restore' },
|
|
||||||
})
|
|
||||||
geojson._umap_options.color = 'Chocolate'
|
|
||||||
fetchMock.get('/datalayer/62/olderversion.geojson', geojson)
|
|
||||||
sinon.spy(window, 'confirm')
|
|
||||||
datalayer.restore('olderversion.geojson')
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert(window.confirm.calledOnce)
|
|
||||||
window.confirm.restore()
|
|
||||||
assert.equal(datalayer.umap_id, 62)
|
|
||||||
assert.ok(datalayer.isDirty)
|
|
||||||
assert.equal(datalayer._index.length, 4)
|
|
||||||
assert.ok(qs('path[fill="Chocolate"]'))
|
|
||||||
done()
|
|
||||||
}, 1000)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should revert anything on cancel click', () => {
|
|
||||||
clickCancel()
|
|
||||||
assert.equal(datalayer._index.length, 3)
|
|
||||||
assert.notOk(qs('path[fill="Chocolate"]'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#smart-options()', () => {
|
|
||||||
let poly, marker
|
|
||||||
before(() => {
|
|
||||||
datalayer.eachLayer(function (layer) {
|
|
||||||
if (!poly && layer instanceof L.Polygon) {
|
|
||||||
poly = layer
|
|
||||||
}
|
|
||||||
if (!marker && layer instanceof L.Marker) {
|
|
||||||
marker = layer
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should parse color variable', () => {
|
|
||||||
let icon = qs('div.umap-div-icon .icon_container')
|
|
||||||
poly.properties.mycolor = 'DarkGoldenRod'
|
|
||||||
marker.properties.mycolor = 'DarkRed'
|
|
||||||
marker.properties._umap_options.color = undefined
|
|
||||||
assert.notOk(qs('path[fill="DarkGoldenRod"]'))
|
|
||||||
assert.equal(icon.style.backgroundColor, 'olivedrab')
|
|
||||||
datalayer.options.color = '{mycolor}'
|
|
||||||
datalayer.options.fillColor = '{mycolor}'
|
|
||||||
datalayer.indexProperties(poly)
|
|
||||||
datalayer.indexProperties(marker)
|
|
||||||
datalayer.redraw()
|
|
||||||
icon = qs('div.umap-div-icon .icon_container')
|
|
||||||
assert.equal(icon.style.backgroundColor, 'darkred')
|
|
||||||
assert.ok(qs('path[fill="DarkGoldenRod"]'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#facet-search()', () => {
|
|
||||||
before(async () => {
|
|
||||||
fetchMock.get(/\/datalayer\/63\/\?.*/, RESPONSES.datalayer63_GET)
|
|
||||||
map.options.facetKey = 'name'
|
|
||||||
await map.initDataLayers([RESPONSES.datalayer63_GET._umap_options])
|
|
||||||
})
|
|
||||||
it('should not impact non browsable layer', () => {
|
|
||||||
assert.ok(qs('path[fill="SteelBlue"]'))
|
|
||||||
})
|
|
||||||
it('should allow advanced filter', () => {
|
|
||||||
map.openFacet()
|
|
||||||
assert.ok(qs('div.umap-facet-search'))
|
|
||||||
// This one if from the normal datalayer
|
|
||||||
// it's name is "test", so it should be hidden
|
|
||||||
// by the filter
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
happen.click(qs('input[data-value="name poly"]'))
|
|
||||||
assert.notOk(qs('path[fill="none"]'))
|
|
||||||
// This one comes from a non browsable layer
|
|
||||||
// so it should not be affected by the filter
|
|
||||||
assert.ok(qs('path[fill="SteelBlue"]'))
|
|
||||||
happen.click(qs('input[data-value="name poly"]')) // Undo
|
|
||||||
})
|
|
||||||
it('should allow to control facet label', () => {
|
|
||||||
map.options.facetKey = 'name|Nom'
|
|
||||||
map.openFacet()
|
|
||||||
assert.ok(qs('div.umap-facet-search h5'))
|
|
||||||
assert.equal(qs('div.umap-facet-search h5').textContent, 'Nom')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
describe('#zoomEnd', () => {
|
|
||||||
it('should honour the fromZoom option', () => {
|
|
||||||
map.setZoom(6, { animate: false })
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
datalayer.options.fromZoom = 6
|
|
||||||
map.setZoom(5, { animate: false })
|
|
||||||
assert.notOk(qs('path[fill="none"]'))
|
|
||||||
map.setZoom(6, { animate: false })
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should honour the toZoom option', () => {
|
|
||||||
map.setZoom(6, { animate: false })
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
datalayer.options.toZoom = 6
|
|
||||||
map.setZoom(7, { animate: false })
|
|
||||||
assert.notOk(qs('path[fill="none"]'))
|
|
||||||
map.setZoom(6, { animate: false })
|
|
||||||
assert.ok(qs('path[fill="none"]'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#displayOnLoad', () => {
|
|
||||||
before(() => {
|
|
||||||
fetchMock.get(/\/datalayer\/64\/\?.*/, RESPONSES.datalayer64_GET)
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await map.initDataLayers([RESPONSES.datalayer64_GET._umap_options])
|
|
||||||
datalayer = map.getDataLayerByUmapId(64)
|
|
||||||
map.setZoom(10, { animate: false })
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
datalayer._delete()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not display layer at load', () => {
|
|
||||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should display on click', (done) => {
|
|
||||||
happen.click(qs(`[data-id='${L.stamp(datalayer)}'] .layer-toggle`))
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert.ok(qs('path[fill="AliceBlue"]'))
|
|
||||||
done()
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should not display on zoom', (done) => {
|
|
||||||
map.setZoom(9, { animate: false })
|
|
||||||
window.setTimeout(() => {
|
|
||||||
assert.notOk(qs('path[fill="AliceBlue"]'))
|
|
||||||
done()
|
|
||||||
}, 500)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('#delete()', () => {
|
|
||||||
let deleteLink,
|
|
||||||
deletePath = '/map/99/datalayer/delete/62/'
|
|
||||||
before(() => {
|
|
||||||
datalayer = map.getDataLayerByUmapId(62)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have a delete link in update form', () => {
|
|
||||||
enableEdit()
|
|
||||||
happen.click(qs('#browse_data_toggle_' + L.stamp(datalayer) + ' .layer-edit'))
|
|
||||||
deleteLink = qs('button.delete_datalayer_button')
|
|
||||||
assert.ok(deleteLink)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should delete features on datalayer delete', () => {
|
|
||||||
happen.click(deleteLink)
|
|
||||||
assert.notOk(qs('div.icon_container'))
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should have set map dirty', () => {
|
|
||||||
assert.ok(map.isDirty)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should delete layer control row on delete', () => {
|
|
||||||
assert.notOk(
|
|
||||||
qs('.leaflet-control-browse #browse_data_toggle_' + L.stamp(datalayer))
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should be removed from map.datalayers_index', () => {
|
|
||||||
assert.equal(map.datalayers_index.indexOf(datalayer), -1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should be removed from map.datalayers', () => {
|
|
||||||
assert.notOk(map.datalayers[L.stamp(datalayer)])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should be visible again on edit cancel', () => {
|
|
||||||
clickCancel()
|
|
||||||
assert.ok(qs('div.icon_container'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
|
@ -89,7 +89,6 @@
|
||||||
</script>
|
</script>
|
||||||
<script src="./_pre.js" defer></script>
|
<script src="./_pre.js" defer></script>
|
||||||
<script src="./Map.js" defer></script>
|
<script src="./Map.js" defer></script>
|
||||||
<script src="./DataLayer.js" defer></script>
|
|
||||||
<script src="./TableEditor.js" defer></script>
|
<script src="./TableEditor.js" defer></script>
|
||||||
<script src="./Feature.js" defer></script>
|
<script src="./Feature.js" defer></script>
|
||||||
<script src="./Marker.js" defer></script>
|
<script src="./Marker.js" defer></script>
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
|
from pathlib import Path
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from playwright.sync_api import expect
|
from playwright.sync_api import expect
|
||||||
|
|
||||||
from umap.models import DataLayer
|
from umap.models import DataLayer, Map
|
||||||
|
|
||||||
from ..base import DataLayerFactory, MapFactory
|
from ..base import DataLayerFactory, MapFactory
|
||||||
|
|
||||||
|
@ -265,3 +267,33 @@ def test_same_second_edit_doesnt_conflict(context, live_server, tilelayer):
|
||||||
"id": str(datalayer.pk),
|
"id": str(datalayer.pk),
|
||||||
"permissions": {"edit_status": 1},
|
"permissions": {"edit_status": 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_display_alert_on_conflict(context, live_server, datalayer, map):
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
|
||||||
|
# Open the map on two pages.
|
||||||
|
page_one = context.new_page()
|
||||||
|
page_one.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
page_two = context.new_page()
|
||||||
|
page_two.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
|
||||||
|
page_one.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
|
||||||
|
page_one.locator('input[name="name"]').fill("new name")
|
||||||
|
with page_one.expect_response(re.compile(r".*/datalayer/update/.*")):
|
||||||
|
page_one.get_by_role("button", name="Save").click()
|
||||||
|
|
||||||
|
page_two.locator(".leaflet-marker-icon").click(modifiers=["Shift"])
|
||||||
|
page_two.locator('input[name="name"]').fill("custom name")
|
||||||
|
with page_two.expect_response(re.compile(r".*/datalayer/update/.*")):
|
||||||
|
page_two.get_by_role("button", name="Save").click()
|
||||||
|
saved = DataLayer.objects.last()
|
||||||
|
data = json.loads(Path(saved.geojson.path).read_text())
|
||||||
|
assert data["features"][0]["properties"]["name"] == "new name"
|
||||||
|
expect(page_two.get_by_text("Woops! Someone else seems to")).to_be_visible()
|
||||||
|
with page_two.expect_response(re.compile(r".*/datalayer/update/.*")):
|
||||||
|
page_two.get_by_role("button", name="Save anyway").click()
|
||||||
|
saved = DataLayer.objects.last()
|
||||||
|
data = json.loads(Path(saved.geojson.path).read_text())
|
||||||
|
assert data["features"][0]["properties"]["name"] == "custom name"
|
||||||
|
|
108
umap/tests/integration/test_datalayer.py
Normal file
108
umap/tests/integration/test_datalayer.py
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from django.core.files.base import ContentFile
|
||||||
|
from playwright.sync_api import expect
|
||||||
|
|
||||||
|
from ..base import DataLayerFactory
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
|
||||||
|
def set_options(datalayer, **options):
|
||||||
|
# For now we need to change both the DB and the FS…
|
||||||
|
datalayer.settings.update(options)
|
||||||
|
data = json.load(datalayer.geojson.file)
|
||||||
|
data["_umap_options"].update(**options)
|
||||||
|
datalayer.geojson = ContentFile(json.dumps(data), "foo.json")
|
||||||
|
datalayer.save()
|
||||||
|
|
||||||
|
|
||||||
|
def test_honour_displayOnLoad_false(map, live_server, datalayer, page):
|
||||||
|
set_options(datalayer, displayOnLoad=False)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||||
|
expect(page.locator(".leaflet-marker-icon")).to_be_hidden()
|
||||||
|
layers = page.locator(".umap-browse-datalayers li")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
layers_off = page.locator(".umap-browse-datalayers li.off")
|
||||||
|
expect(layers).to_have_count(1)
|
||||||
|
expect(layers_off).to_have_count(1)
|
||||||
|
page.get_by_role("button", name="See data layers").click()
|
||||||
|
page.get_by_label("Zoom in").click()
|
||||||
|
expect(markers).to_be_hidden()
|
||||||
|
page.get_by_title("Show/hide layer").click()
|
||||||
|
expect(layers_off).to_have_count(0)
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_honour_fromZoom(live_server, map, datalayer, page):
|
||||||
|
set_options(datalayer, displayOnLoad=True, fromZoom=6)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}#5/48.55/14.68")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(markers).to_be_hidden()
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.55/14.68")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
page.get_by_label("Zoom out").click()
|
||||||
|
expect(markers).to_be_hidden()
|
||||||
|
page.get_by_label("Zoom in").click()
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
page.get_by_label("Zoom in").click()
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_honour_toZoom(live_server, map, datalayer, page):
|
||||||
|
set_options(datalayer, displayOnLoad=True, toZoom=6)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}#7/48.55/14.68")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(markers).to_be_hidden()
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}#6/48.55/14.68")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
page.get_by_label("Zoom out").click()
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
page.get_by_label("Zoom in").click()
|
||||||
|
expect(markers).to_be_visible()
|
||||||
|
page.get_by_label("Zoom in").click()
|
||||||
|
# FIXME does not work (but works when using PWDEBUG=1), not sure why
|
||||||
|
# may be a race condition related to css transition
|
||||||
|
# expect(markers).to_be_hidden()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_honour_color_variable(live_server, map, page):
|
||||||
|
data = {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {"mycolor": "aliceblue", "name": "Point 4"},
|
||||||
|
"geometry": {"type": "Point", "coordinates": [0.856934, 45.290347]},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {"name": "a polygon", "mycolor": "tomato"},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Polygon",
|
||||||
|
"coordinates": [
|
||||||
|
[
|
||||||
|
[2.12, 49.57],
|
||||||
|
[1.08, 49.02],
|
||||||
|
[2.51, 47.55],
|
||||||
|
[3.19, 48.77],
|
||||||
|
[2.12, 49.57],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"_umap_options": {
|
||||||
|
"name": "Calque 2",
|
||||||
|
"color": "{mycolor}",
|
||||||
|
"fillColor": "{mycolor}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
DataLayerFactory(map=map, data=data)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||||
|
expect(page.locator(".leaflet-overlay-pane path[fill='tomato']"))
|
||||||
|
markers = page.locator(".leaflet-marker-icon .icon_container")
|
||||||
|
expect(markers).to_have_css("background-color", "rgb(240, 248, 255)")
|
|
@ -1,5 +1,11 @@
|
||||||
|
import re
|
||||||
|
|
||||||
from playwright.sync_api import expect
|
from playwright.sync_api import expect
|
||||||
|
|
||||||
|
from umap.models import DataLayer, Map
|
||||||
|
|
||||||
|
from ..base import DataLayerFactory
|
||||||
|
|
||||||
|
|
||||||
def test_should_have_fieldset_for_layer_type_properties(page, live_server, tilelayer):
|
def test_should_have_fieldset_for_layer_type_properties(page, live_server, tilelayer):
|
||||||
page.goto(f"{live_server.url}/en/map/new/")
|
page.goto(f"{live_server.url}/en/map/new/")
|
||||||
|
@ -44,3 +50,145 @@ def test_should_have_fieldset_for_layer_type_properties(page, live_server, tilel
|
||||||
expect(choropleth_header).to_be_hidden()
|
expect(choropleth_header).to_be_hidden()
|
||||||
expect(heat_header).to_be_hidden()
|
expect(heat_header).to_be_hidden()
|
||||||
expect(cluster_header).to_be_hidden()
|
expect(cluster_header).to_be_hidden()
|
||||||
|
|
||||||
|
|
||||||
|
def test_cancel_deleting_datalayer_should_restore(
|
||||||
|
live_server, map, login, datalayer, page
|
||||||
|
):
|
||||||
|
# Faster than doing a login
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
layers = page.locator(".umap-browse-datalayers li")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(layers).to_have_count(1)
|
||||||
|
expect(markers).to_have_count(1)
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.once("dialog", lambda dialog: dialog.accept())
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Delete layer").click()
|
||||||
|
expect(markers).to_have_count(0)
|
||||||
|
page.get_by_role("button", name="See data layers").click()
|
||||||
|
expect(page.get_by_text("test datalayer")).to_be_hidden()
|
||||||
|
page.once("dialog", lambda dialog: dialog.accept())
|
||||||
|
page.get_by_role("button", name="Cancel edits").click()
|
||||||
|
expect(markers).to_have_count(1)
|
||||||
|
expect(
|
||||||
|
page.locator(".leaflet-control-browse").get_by_text("test datalayer")
|
||||||
|
).to_be_visible()
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_clone_datalayer(live_server, map, login, datalayer, page):
|
||||||
|
# Faster than doing a login
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
layers = page.locator(".umap-browse-datalayers li")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(layers).to_have_count(1)
|
||||||
|
expect(markers).to_have_count(1)
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
|
||||||
|
page.get_by_role("heading", name="Advanced actions").click()
|
||||||
|
page.get_by_role("button", name="Clone").click()
|
||||||
|
expect(layers).to_have_count(2)
|
||||||
|
expect(markers).to_have_count(2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_change_icon_class(live_server, map, page):
|
||||||
|
# Faster than doing a login
|
||||||
|
data = {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {"name": "Point 4"},
|
||||||
|
"geometry": {"type": "Point", "coordinates": [0.856934, 45.290347]},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
DataLayerFactory(map=map, data=data)
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
expect(page.locator(".umap-div-icon")).to_be_visible()
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
expect(page.locator(".umap-circle-icon")).to_be_hidden()
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
|
||||||
|
page.get_by_role("heading", name="Shape properties").click()
|
||||||
|
page.locator(".umap-field-iconClass a.define").click()
|
||||||
|
page.get_by_text("Circle").click()
|
||||||
|
expect(page.locator(".umap-circle-icon")).to_be_visible()
|
||||||
|
expect(page.locator(".umap-div-icon")).to_be_hidden()
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_change_name(live_server, map, page, datalayer):
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
page.goto(
|
||||||
|
f"{live_server.url}{map.get_absolute_url()}?edit&datalayersControl=expanded"
|
||||||
|
)
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
|
||||||
|
expect(page.locator(".umap-is-dirty")).to_be_hidden()
|
||||||
|
page.locator('input[name="name"]').click()
|
||||||
|
page.locator('input[name="name"]').press("Control+a")
|
||||||
|
page.locator('input[name="name"]').fill("new name")
|
||||||
|
expect(page.locator(".leaflet-control-browse li span")).to_contain_text("new name")
|
||||||
|
expect(page.locator(".umap-is-dirty")).to_be_visible()
|
||||||
|
with page.expect_response(re.compile(".*/datalayer/update/.*")):
|
||||||
|
page.get_by_role("button", name="Save").click()
|
||||||
|
saved = DataLayer.objects.last()
|
||||||
|
assert saved.name == "new name"
|
||||||
|
expect(page.locator(".umap-is-dirty")).to_be_hidden()
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_create_new_datalayer(live_server, map, page, datalayer):
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
page.goto(
|
||||||
|
f"{live_server.url}{map.get_absolute_url()}?edit&datalayersControl=expanded"
|
||||||
|
)
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.get_by_role("button", name="Add a layer").click()
|
||||||
|
page.locator('input[name="name"]').click()
|
||||||
|
page.locator('input[name="name"]').fill("my new layer")
|
||||||
|
expect(page.get_by_text("my new layer")).to_be_visible()
|
||||||
|
with page.expect_response(re.compile(".*/datalayer/create/.*")):
|
||||||
|
page.get_by_role("button", name="Save").click()
|
||||||
|
assert DataLayer.objects.count() == 2
|
||||||
|
saved = DataLayer.objects.last()
|
||||||
|
assert saved.name == "my new layer"
|
||||||
|
expect(page.locator(".umap-is-dirty")).to_be_hidden()
|
||||||
|
# Edit again, it should not create a new datalayer
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Edit", exact=True).first.click()
|
||||||
|
page.locator('input[name="name"]').click()
|
||||||
|
page.locator('input[name="name"]').fill("my new layer with a new name")
|
||||||
|
expect(page.get_by_text("my new layer with a new name")).to_be_visible()
|
||||||
|
page.get_by_role("button", name="Save").click()
|
||||||
|
with page.expect_response(re.compile(".*/datalayer/update/.*")):
|
||||||
|
page.get_by_role("button", name="Save").click()
|
||||||
|
assert DataLayer.objects.count() == 2
|
||||||
|
saved = DataLayer.objects.last()
|
||||||
|
assert saved.name == "my new layer with a new name"
|
||||||
|
expect(page.locator(".umap-is-dirty")).to_be_hidden()
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_restore_version(live_server, map, page, datalayer):
|
||||||
|
map.edit_status = Map.ANONYMOUS
|
||||||
|
map.save()
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
marker = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
|
||||||
|
marker.click(modifiers=["Shift"])
|
||||||
|
page.get_by_role("heading", name="Shape properties").click()
|
||||||
|
page.locator("#umap-feature-shape-properties").get_by_text("Default").click()
|
||||||
|
with page.expect_response(re.compile(".*/datalayer/update/.*")):
|
||||||
|
page.get_by_role("button", name="Save").click()
|
||||||
|
expect(marker).to_have_class(re.compile(".*umap-div-icon.*"))
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Edit", exact=True).click()
|
||||||
|
page.get_by_role("heading", name="Versions").click()
|
||||||
|
page.once("dialog", lambda dialog: dialog.accept())
|
||||||
|
page.get_by_role("button", name="Restore this version").last.click()
|
||||||
|
expect(marker).to_have_class(re.compile(".*umap-ball-icon.*"))
|
||||||
|
|
|
@ -46,6 +46,30 @@ DATALAYER_DATA2 = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DATALAYER_DATA3 = {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"properties": {"name": "a polygon"},
|
||||||
|
"geometry": {
|
||||||
|
"type": "Polygon",
|
||||||
|
"coordinates": [
|
||||||
|
[
|
||||||
|
[2.12, 49.57],
|
||||||
|
[1.08, 49.02],
|
||||||
|
[2.51, 47.55],
|
||||||
|
[3.19, 48.77],
|
||||||
|
[2.12, 49.57],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"_umap_options": {"name": "Calque 2", "browsable": False},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def bootstrap(map, live_server):
|
def bootstrap(map, live_server):
|
||||||
map.settings["properties"]["onLoadPanel"] = "facet"
|
map.settings["properties"]["onLoadPanel"] = "facet"
|
||||||
|
@ -54,11 +78,15 @@ def bootstrap(map, live_server):
|
||||||
map.save()
|
map.save()
|
||||||
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
DataLayerFactory(map=map, data=DATALAYER_DATA1)
|
||||||
DataLayerFactory(map=map, data=DATALAYER_DATA2)
|
DataLayerFactory(map=map, data=DATALAYER_DATA2)
|
||||||
|
DataLayerFactory(map=map, data=DATALAYER_DATA3)
|
||||||
|
|
||||||
|
|
||||||
def test_simple_facet_search(live_server, page, bootstrap, map):
|
def test_simple_facet_search(live_server, page, bootstrap, map):
|
||||||
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
page.goto(f"{live_server.url}{map.get_absolute_url()}")
|
||||||
panel = page.locator(".umap-facet-search")
|
panel = page.locator(".umap-facet-search")
|
||||||
|
# From a non browsable datalayer, should not be impacted
|
||||||
|
paths = page.locator(".leaflet-overlay-pane path")
|
||||||
|
expect(paths).to_be_visible
|
||||||
expect(panel).to_be_visible()
|
expect(panel).to_be_visible()
|
||||||
# Facet name
|
# Facet name
|
||||||
expect(page.get_by_text("My type")).to_be_visible()
|
expect(page.get_by_text("My type")).to_be_visible()
|
||||||
|
@ -67,6 +95,7 @@ def test_simple_facet_search(live_server, page, bootstrap, map):
|
||||||
odd = page.get_by_text("odd")
|
odd = page.get_by_text("odd")
|
||||||
expect(oven).to_be_visible()
|
expect(oven).to_be_visible()
|
||||||
expect(odd).to_be_visible()
|
expect(odd).to_be_visible()
|
||||||
|
expect(paths).to_be_visible
|
||||||
markers = page.locator(".leaflet-marker-icon")
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
expect(markers).to_have_count(4)
|
expect(markers).to_have_count(4)
|
||||||
# Tooltips
|
# Tooltips
|
||||||
|
@ -81,6 +110,8 @@ def test_simple_facet_search(live_server, page, bootstrap, map):
|
||||||
expect(page.get_by_text("Point 4")).to_be_hidden()
|
expect(page.get_by_text("Point 4")).to_be_hidden()
|
||||||
expect(page.get_by_text("Point 1")).to_be_visible()
|
expect(page.get_by_text("Point 1")).to_be_visible()
|
||||||
expect(page.get_by_text("Point 3")).to_be_visible()
|
expect(page.get_by_text("Point 3")).to_be_visible()
|
||||||
|
expect(paths).to_be_visible
|
||||||
# Now let's filter
|
# Now let's filter
|
||||||
odd.click()
|
odd.click()
|
||||||
expect(markers).to_have_count(4)
|
expect(markers).to_have_count(4)
|
||||||
|
expect(paths).to_be_visible
|
||||||
|
|
|
@ -231,3 +231,21 @@ def test_can_change_owner(map, live_server, login, user):
|
||||||
save.click()
|
save.click()
|
||||||
modified = Map.objects.get(pk=map.pk)
|
modified = Map.objects.get(pk=map.pk)
|
||||||
assert modified.owner == user
|
assert modified.owner == user
|
||||||
|
|
||||||
|
|
||||||
|
def test_can_delete_datalayer(live_server, map, login, datalayer):
|
||||||
|
page = login(map.owner)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}?edit")
|
||||||
|
layers = page.locator(".umap-browse-datalayers li")
|
||||||
|
markers = page.locator(".leaflet-marker-icon")
|
||||||
|
expect(layers).to_have_count(1)
|
||||||
|
expect(markers).to_have_count(1)
|
||||||
|
page.get_by_role("link", name="Manage layers").click()
|
||||||
|
page.once("dialog", lambda dialog: dialog.accept())
|
||||||
|
page.locator("#umap-ui-container").get_by_title("Delete layer").click()
|
||||||
|
with page.expect_response(re.compile(r".*/datalayer/delete/.*")):
|
||||||
|
page.get_by_role("button", name="Save").click()
|
||||||
|
expect(markers).to_have_count(0)
|
||||||
|
# FIXME does not work, resolve to 1 element, even if this command is empty:
|
||||||
|
# document.querySelectorAll(".umap-browse-datalayers li")
|
||||||
|
# expect(layers).to_have_count(0)
|
||||||
|
|
Loading…
Reference in a new issue