Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions assets/src/modules/Geolocation.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ export default class Geolocation {

// Get position in GPS coordinates (ESPG:4326) with 6 decimals
get position() {
if (!this.isTracking) {
return undefined;
}
const position = this._geolocation.getPosition();
if (position) {
const qgisProjectProjection = this._lizmap3.map.getProjection();
Expand All @@ -171,8 +174,12 @@ export default class Geolocation {
}

get accuracy() {
if (this._geolocation.getAccuracy()) {
return parseFloat(this._geolocation.getAccuracy().toFixed(3));
if (!this.isTracking) {
return undefined;
}
const acc = this._geolocation.getAccuracy();
if (acc) {
return parseFloat(acc.toFixed(3));
}
return undefined;
}
Expand Down
253 changes: 253 additions & 0 deletions tests/end2end/playwright/geolocation.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
// @ts-check
import { dirname } from 'path';
import * as fs from 'fs/promises'
import { existsSync } from 'node:fs';
import { test, expect } from '@playwright/test';
import { ProjectPage } from './pages/project';
import { playwrightTestFile, digestBuffer } from "./globals";

// To update OSM and GeoPF tiles in the mock directory
// IMPORTANT, this must not be set to `true` while committing, on GitHub. Set to `false`.
const UPDATE_MOCK_FILES = false;

test.describe('Geolocation @readonly', () => {

const locale = 'en-US';

/** @type {string[]} */
let osmTiles = [];

test.beforeEach(async ({ page }) => {
const project = new ProjectPage(page, 'geolocation');
project.waitForGetLegendGraphicDuringLoad = false;
project.layersInTreeView = 0;

// Catch all tiles requests from openstreetmap to mock them
await page.route('https://tile.openstreetmap.org/*/*/*.png', async (route) => {
const request = route.request();
osmTiles.push(request.url());

// Build path file in mock directory
const pathFile = playwrightTestFile('mock', 'geolocation', 'osm', 'tiles' + (new URL(request.url()).pathname));
if (UPDATE_MOCK_FILES) {
// Save file in mock directory
const response = await route.fetch();
await fs.mkdir(dirname(pathFile), { recursive: true });
await fs.writeFile(pathFile, new Uint8Array(await response.body()));
} else if (existsSync(pathFile)) {
// fulfill route's request with mock file
await route.fulfill({
path: pathFile
})
} else {
// fulfill route's request with default transparent tile
await route.fulfill({
path: playwrightTestFile('mock', 'transparent_tile.png')
})
}
});

await project.open();
});

test.afterEach(async ({ page }) => {
osmTiles = [];
await page.unroute('https://tile.openstreetmap.org/*/*/*.png');
});

test('Geolocation Default UI', async ({ page }) => {
//const project = new ProjectPage(page, 'geolocation');

// Grant geolocation permission and set geolocation
page.context().grantPermissions(['geolocation']);
page.context().setGeolocation({
latitude: 43.6214338643574,
longitude: 3.84280215159599,
accuracy: 100,
});

// Check scale
await expect(page.locator('#overview-bar .ol-scale-text')).toHaveText('1 : ' + (50000000).toLocaleString(locale));

// Check button to open geolocation
const geolocationButton = page.locator('#button-geolocation');
await expect(geolocationButton).toBeVisible();
await geolocationButton.click();

// Check dock
const geolocationDock = page.locator('#geolocation');
await expect(geolocationDock).toBeVisible();
await expect(geolocationDock.locator('.title .text')).toHaveText('Geolocation');
const geolocationDockButtonBar = geolocationDock.locator('.button-bar');
await expect(geolocationDockButtonBar).toBeVisible();
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true })).toHaveCount(1);
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true })).toBeVisible();
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Center', exact: true })).toHaveCount(1);
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Center', exact: true })).toBeVisible();
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Stay centered', exact: true })).toHaveCount(1);
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Stay centered', exact: true })).toBeVisible();
await expect(geolocationDockButtonBar.locator('input')).toHaveCount(1);
await expect(geolocationDockButtonBar.locator('input')).toBeVisible();
await expect(geolocationDockButtonBar.locator('input')).toHaveValue('10');
const geolocationDockInfos = geolocationDock.locator('.geolocation-infos');
await expect(geolocationDockInfos).toBeVisible();
const geolocationDockCoords = geolocationDock.locator('.geolocation-coords');
await expect(geolocationDockCoords).toBeVisible();
await expect(geolocationDockCoords.locator('div')).toHaveCount(2);
await expect(geolocationDockCoords.locator('div').nth(0)).toHaveText('X :');
await expect(geolocationDockCoords.locator('div').nth(1)).toHaveText('Y :');
const geolocationDockAccuracy = geolocationDock.locator('.geolocation-accuracy');
await expect(geolocationDockAccuracy).toBeVisible();
await expect(geolocationDockAccuracy).toHaveText('Accuracy (m) :');
});

test('Geolocation start and stop', async ({ page }) => {
const project = new ProjectPage(page, 'geolocation');
const screenshotClip = {x:850/2-380/2, y:700/2-380/2, width:380, height:380};

// Wait for request and response
while (osmTiles.length < 12) {
await page.waitForResponse('https://tile.openstreetmap.org/*/*/*.png', { timeout: 10000 });
}

// Grant geolocation permission and set geolocation
page.context().grantPermissions(['geolocation']);
page.context().setGeolocation({
latitude: 43.6214338643574,
longitude: 3.84280215159599,
accuracy: 1000,
});

const geolocationButton = page.locator('#button-geolocation');
await geolocationButton.click();

// Catch osm tile
/** @type {string[]} */
osmTiles = [];

// Start geolocation
const geolocationDock = page.locator('#geolocation');
const geolocationDockButtonBar = geolocationDock.locator('.button-bar');
await geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true }).click();

// check dock
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true })).toHaveCount(0);
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Stop', exact: true })).toHaveCount(1);
const geolocationDockCoords = geolocationDock.locator('.geolocation-coords');
await expect(geolocationDockCoords.locator('div').nth(0)).toHaveText('X : 3.842802');
await expect(geolocationDockCoords.locator('div').nth(1)).toHaveText('Y : 43.621434');
const geolocationDockAccuracy = geolocationDock.locator('.geolocation-accuracy');
await expect(geolocationDockAccuracy).toHaveText('Accuracy (m) : 1000');

// Check scale
await expect(page.locator('#overview-bar .ol-scale-text')).toHaveText('1 : ' + (25000).toLocaleString(locale));

// Wait for request and response
while (osmTiles.length < 6) {
await page.waitForResponse('https://tile.openstreetmap.org/*/*/*.png', { timeout: 10000 });
}

// Check that we catch 6 tiles
expect(osmTiles.length).toBeGreaterThanOrEqual(6);
// Check that every tiles are from level 19
expect(osmTiles[0]).toMatch(/\/15\/\d{5}\/\d{5}\.png/)
expect(osmTiles[1]).toMatch(/\/15\/\d{5}\/\d{5}\.png/)
expect(osmTiles[2]).toMatch(/\/15\/\d{5}\/\d{5}\.png/)
expect(osmTiles[3]).toMatch(/\/15\/\d{5}\/\d{5}\.png/)
expect(osmTiles[4]).toMatch(/\/15\/\d{5}\/\d{5}\.png/)
expect(osmTiles[5]).toMatch(/\/15\/\d{5}\/\d{5}\.png/)

// Blank map
await project.baseLayerSelect.selectOption('project-background-color');
await expect(project.baseLayerSelect).toHaveValue('project-background-color');

// Wait for OL transition
await page.waitForTimeout(500);

// Get acc 1000 buffer
let buffer = await page.screenshot({
clip: screenshotClip,
// path: playwrightTestFile('__screenshots__','geolocation.spec.js','pos.png'),
});
const acc1000Hash = await digestBuffer(buffer);
const acc1000ByteLength = buffer.byteLength;
expect(acc1000ByteLength).toBeGreaterThan(4000); // 4161 - 5471
expect(acc1000ByteLength).toBeLessThan(6000); // 4161 - 5471

// Stop geolocation
await geolocationDockButtonBar.getByRole('button', { name: 'Stop', exact: true }).click();

// Get blank buffer
buffer = await page.screenshot({
clip: screenshotClip,
// path: playwrightTestFile('__screenshots__','geolocation.spec.js','blank.png'),
});
const blankHash = await digestBuffer(buffer);
expect(blankHash).not.toBe(acc1000Hash);
const blankByteLength = buffer.byteLength;
expect(blankByteLength).toBeLessThan(acc1000ByteLength);
expect(blankByteLength).toBeGreaterThan(1000); // 1286
expect(blankByteLength).toBeLessThan(1500); // 1286

// check dock
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Stop', exact: true })).toHaveCount(0);
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true })).toHaveCount(1);
await expect(geolocationDockCoords.locator('div').nth(0)).toHaveText('X :');
await expect(geolocationDockCoords.locator('div').nth(1)).toHaveText('Y :');
await expect(geolocationDockAccuracy).toHaveText('Accuracy (m) :');

// Change accuracy
page.context().setGeolocation({
latitude: 43.6214338643574,
longitude: 3.84280215159599,
accuracy: 100,
});

// Catch osm tile
osmTiles = [];

// Restart on new accuracy
await geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true }).click();

// check dock
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Start', exact: true })).toHaveCount(0);
await expect(geolocationDockButtonBar.getByRole('button', { name: 'Stop', exact: true })).toHaveCount(1);
await expect(geolocationDockCoords.locator('div').nth(0)).toHaveText('X : 3.842802');
await expect(geolocationDockCoords.locator('div').nth(1)).toHaveText('Y : 43.621434');
await expect(geolocationDockAccuracy).toHaveText('Accuracy (m) : 100');

// Check scale
await expect(page.locator('#overview-bar .ol-scale-text')).toHaveText('1 : ' + (25000).toLocaleString(locale));

// Get acc 100 buffer
buffer = await page.screenshot({
clip: screenshotClip,
// path: playwrightTestFile('__screenshots__','geolocation.spec.js','blank.png'),
});
const acc100Hash = await digestBuffer(buffer);
expect(acc100Hash).not.toBe(acc1000Hash);
expect(acc100Hash).not.toBe(blankHash);
const acc100ByteLength = buffer.byteLength;
expect(acc100ByteLength).toBeGreaterThan(blankByteLength);
expect(acc100ByteLength).toBeLessThan(acc1000ByteLength);
expect(acc100ByteLength).toBeGreaterThan(1750); // 1911
expect(acc100ByteLength).toBeLessThan(2250); // 1911

// Wait for request and response
// while (osmTiles.length < 6) {
// await page.waitForResponse('https://tile.openstreetmap.org/*/*/*.png', { timeout: 10000 });
// }

/*
// Check that we catch 6 tiles
expect(osmTiles.length).toBeGreaterThanOrEqual(6);
// Check that every tiles are from level 19
expect(osmTiles[0]).toMatch(/\/19\/\d{6}\/\d{6}\.png/);
expect(osmTiles[1]).toMatch(/\/19\/\d{6}\/\d{6}\.png/);
expect(osmTiles[2]).toMatch(/\/19\/\d{6}\/\d{6}\.png/);
expect(osmTiles[3]).toMatch(/\/19\/\d{6}\/\d{6}\.png/);
expect(osmTiles[4]).toMatch(/\/19\/\d{6}\/\d{6}\.png/);
expect(osmTiles[5]).toMatch(/\/19\/\d{6}\/\d{6}\.png/);
*/
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/qgis-projects/tests/geolocation.qgs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
<wgs84extent>
<xmin>-180</xmin>
<ymin>-85.05112877980660357</ymin>
<xmax>179.99999999999997158</xmax>
<xmax>180</xmax>
<ymax>85.05112877980660357</ymax>
</wgs84extent>
<id>OpenStreetMap_ab9cd479_708a_4147_a0b1_2508e7ba864c</id>
Expand Down
12 changes: 8 additions & 4 deletions tests/qgis-projects/tests/geolocation.qgs.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"12514194.88550000078976154"
],
"mapScales": [
500,
1000,
10000,
25000,
50000,
Expand All @@ -34,10 +36,10 @@
10000000,
50000000
],
"minScale": 10000,
"minScale": 500,
"maxScale": 50000000,
"use_native_zoom_levels": false,
"hide_numeric_scale_value": true,
"hide_numeric_scale_value": false,
"initialExtent": [
-14501160.6436,
-6445735.3992,
Expand All @@ -57,8 +59,7 @@
"datavizLocation": "dock",
"theme": "dark",
"fixed_scale_overview_map": true,
"dataviz_drag_drop": [],
"default_background_color_index": 1
"dataviz_drag_drop": []
},
"layers": {
"baselayers": {
Expand All @@ -75,6 +76,7 @@
"popupSource": "auto",
"popupTemplate": "",
"popupMaxFeatures": 10,
"children_lizmap_features_table": false,
"popupDisplayChildren": "False",
"popup_allow_download": true,
"legend_image_option": "hide_at_startup",
Expand Down Expand Up @@ -108,6 +110,7 @@
"popupSource": "auto",
"popupTemplate": "",
"popupMaxFeatures": 10,
"children_lizmap_features_table": false,
"popupDisplayChildren": "False",
"popup_allow_download": true,
"legend_image_option": "hide_at_startup",
Expand All @@ -134,6 +137,7 @@
"popupSource": "auto",
"popupTemplate": "",
"popupMaxFeatures": 10,
"children_lizmap_features_table": false,
"popupDisplayChildren": "False",
"popup_allow_download": true,
"legend_image_option": "hide_at_startup",
Expand Down
Loading