Adding some first unit test and managing translations with scale=1
This commit is contained in:
parent
3a7d4987a3
commit
67e4d13989
|
@ -20,6 +20,7 @@ const Map: react.FC<{}> = (props: {}) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener('resize', debouncedResizeHandler);
|
window.addEventListener('resize', debouncedResizeHandler);
|
||||||
|
// dispatch(mapActions.shift({ x: -50, y: 0 }));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||||
|
// allows you to do things like:
|
||||||
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
|
||||||
|
// Mock matchmedia
|
||||||
|
window.matchMedia = window.matchMedia || function() {
|
||||||
|
return {
|
||||||
|
matches: false,
|
||||||
|
addListener: function() {},
|
||||||
|
removeListener: function() {}
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,69 @@
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { initialMapState, reevaluateState } from './map';
|
||||||
|
|
||||||
|
//interface CustomMatchers<R = unknown> {
|
||||||
|
// isDeepEqual(received: any, target: any): R;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//declare global {
|
||||||
|
// namespace jest {
|
||||||
|
// interface Expect extends CustomMatchers {}
|
||||||
|
// interface Matchers<R> extends CustomMatchers<R> {}
|
||||||
|
// interface InverseAsymmetricMatchers extends CustomMatchers {}
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
expect.extend({
|
||||||
|
isDeepEqual: (received: any, target: any) => {
|
||||||
|
const pass = _.isEqual(received, target);
|
||||||
|
if (pass) {
|
||||||
|
return { message: () => '', pass: true };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
message: () =>
|
||||||
|
`${JSON.stringify(received)} instead of\n ${JSON.stringify(target)}`,
|
||||||
|
pass: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
isAlmostDeepEqual: (received: any, target: any, delta: number) => {
|
||||||
|
const pass = _.isEqualWith(received, target, (r: any, t: any) => {
|
||||||
|
if (typeof r !== 'number' || typeof t !== 'number') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
console.log(`r: ${r}, t:${t}, ${Math.abs(r - t) <= delta}`);
|
||||||
|
return Math.abs(r - t) <= delta;
|
||||||
|
});
|
||||||
|
if (pass) {
|
||||||
|
return { message: () => '', pass: true };
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
message: () =>
|
||||||
|
`${JSON.stringify(received)} instead of\n ${JSON.stringify(target)}`,
|
||||||
|
pass: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Our isAlmostDeepEqual matcher', () => {
|
||||||
|
test('compares correctly two numbers that are almost equals', () => {
|
||||||
|
expect({ x: 1.001 }).isAlmostDeepEqual({ x: 1 }, 1e-2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Map store methods', () => {
|
||||||
|
test('initialize its state', () => {
|
||||||
|
const state = _.cloneDeep(initialMapState);
|
||||||
|
expect(state.tiles.nb.x).not.toBe(0);
|
||||||
|
});
|
||||||
|
test('reevaluateState keeps the same values', () => {
|
||||||
|
const state = _.cloneDeep(initialMapState);
|
||||||
|
reevaluateState(state);
|
||||||
|
expect(state).isAlmostDeepEqual(initialMapState, 1e-7);
|
||||||
|
});
|
||||||
|
test('reevaluateState computes the right longitude after a shift 50 pixels left', () => {
|
||||||
|
const state = _.cloneDeep(initialMapState);
|
||||||
|
state.slippy.translation.x = state.slippy.translation.x - 50;
|
||||||
|
reevaluateState(state);
|
||||||
|
expect(state.scope.center.lon).not.toBe(77.5539501);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,7 +1,14 @@
|
||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { tileSize } from '../components/map/tiled-map';
|
import { tileSize } from '../components/map/tiled-map';
|
||||||
import { geoPoint, Point, lon2tile, lat2tile } from '../lib/geo';
|
import {
|
||||||
|
geoPoint,
|
||||||
|
Point,
|
||||||
|
lon2tile,
|
||||||
|
lat2tile,
|
||||||
|
tile2lat,
|
||||||
|
tile2long,
|
||||||
|
} from '../lib/geo';
|
||||||
|
|
||||||
// Top level properties (the other properties can be derived from them)
|
// Top level properties (the other properties can be derived from them)
|
||||||
|
|
||||||
|
@ -12,7 +19,7 @@ export interface MapScope {
|
||||||
}
|
}
|
||||||
const initialMapScope: MapScope = {
|
const initialMapScope: MapScope = {
|
||||||
center: { lat: -37.8403508, lon: 77.5539501 },
|
center: { lat: -37.8403508, lon: 77.5539501 },
|
||||||
zoom: 13.49,
|
zoom: 13,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Derived properties
|
// Derived properties
|
||||||
|
@ -60,7 +67,7 @@ const nbTilesY = _.ceil(mapState.viewport.height / tileSize) + 4;
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let initialMapState: MapState = {
|
export var initialMapState: MapState = {
|
||||||
scope: initialMapScope,
|
scope: initialMapScope,
|
||||||
slippy: {
|
slippy: {
|
||||||
scale: 1,
|
scale: 1,
|
||||||
|
@ -82,7 +89,8 @@ let initialMapState: MapState = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const evaluateStateFromScope = (state: MapState) => {
|
export const evaluateStateFromScope = (state: MapState) => {
|
||||||
|
console.log('<<<<<<<<<<<< evaluateStateFromScope');
|
||||||
state.tiles.zoom = _.round(state.scope.zoom);
|
state.tiles.zoom = _.round(state.scope.zoom);
|
||||||
const softZoom = state.scope.zoom - state.tiles.zoom;
|
const softZoom = state.scope.zoom - state.tiles.zoom;
|
||||||
state.slippy.scale = 2 ** softZoom;
|
state.slippy.scale = 2 ** softZoom;
|
||||||
|
@ -115,9 +123,37 @@ const evaluateStateFromScope = (state: MapState) => {
|
||||||
|
|
||||||
evaluateStateFromScope(initialMapState);
|
evaluateStateFromScope(initialMapState);
|
||||||
|
|
||||||
const reevaluateState = (state: MapState) => {};
|
export const reevaluateState = (state: MapState) => {
|
||||||
|
// Update the scope (center and zoom level)
|
||||||
|
const centerPX = {
|
||||||
|
x: window.innerWidth / 2,
|
||||||
|
y: window.innerHeight / 2,
|
||||||
|
};
|
||||||
|
const visibleTileSize = tileSize / state.slippy.scale;
|
||||||
|
const centerTiles = {
|
||||||
|
x:
|
||||||
|
state.tiles.first.x +
|
||||||
|
(centerPX.x - state.slippy.translation.x) / visibleTileSize,
|
||||||
|
y:
|
||||||
|
state.tiles.first.y +
|
||||||
|
(centerPX.y - state.slippy.translation.y) / visibleTileSize,
|
||||||
|
};
|
||||||
|
state.scope.center = {
|
||||||
|
lat: tile2lat(centerTiles.y, state.tiles.zoom),
|
||||||
|
lon: tile2long(centerTiles.x, state.tiles.zoom),
|
||||||
|
};
|
||||||
|
// TODO: zoom level
|
||||||
|
if (
|
||||||
|
-state.slippy.translation.x < visibleTileSize ||
|
||||||
|
-state.slippy.translation.y < visibleTileSize ||
|
||||||
|
-state.slippy.translation.x >
|
||||||
|
(state.tiles.nb.x - 1) * visibleTileSize - window.innerWidth ||
|
||||||
|
-state.slippy.translation.y >
|
||||||
|
(state.tiles.nb.y - 1) * visibleTileSize - window.innerHeight
|
||||||
|
) {
|
||||||
|
evaluateStateFromScope(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const mapSlice = createSlice({
|
const mapSlice = createSlice({
|
||||||
name: 'map',
|
name: 'map',
|
||||||
|
@ -131,6 +167,7 @@ const mapSlice = createSlice({
|
||||||
x: state.slippy.translation.x + action.payload.x,
|
x: state.slippy.translation.x + action.payload.x,
|
||||||
y: state.slippy.translation.y + action.payload.y,
|
y: state.slippy.translation.y + action.payload.y,
|
||||||
};
|
};
|
||||||
|
reevaluateState(state);
|
||||||
},
|
},
|
||||||
scale: (state, action) => {
|
scale: (state, action) => {
|
||||||
state.slippy.scale = state.slippy.scale * action.payload.factor;
|
state.slippy.scale = state.slippy.scale * action.payload.factor;
|
||||||
|
@ -144,6 +181,7 @@ const mapSlice = createSlice({
|
||||||
(state.slippy.translation.y - action.payload.center.y) *
|
(state.slippy.translation.y - action.payload.center.y) *
|
||||||
(action.payload.factor - 1),
|
(action.payload.factor - 1),
|
||||||
};
|
};
|
||||||
|
reevaluateState(state);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue