mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-30 17:00:35 +02:00
Merge branch 'kh/vitest' into develop
This commit is contained in:
@@ -1,109 +0,0 @@
|
||||
// Karma configuration
|
||||
// Generated on Wed Sep 01 2021 16:45:06 GMT+0200 (Central European Summer Time)
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
basePath: '..',
|
||||
|
||||
plugins: [
|
||||
'karma-remap-istanbul',
|
||||
'karma-coverage',
|
||||
'karma-mocha',
|
||||
'karma-chrome-launcher'
|
||||
],
|
||||
|
||||
// frameworks to use
|
||||
// available frameworks: https://www.npmjs.com/search?q=keywords:karma-adapter
|
||||
frameworks: ['mocha'],
|
||||
|
||||
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
'node_modules/chai/chai.js',
|
||||
'node_modules/sinon/pkg/sinon.js',
|
||||
'node_modules/sinon-chai/lib/sinon-chai.js',
|
||||
'node_modules/happen/happen.js',
|
||||
'node_modules/fetch-mock/es5/client-bundle.js',
|
||||
{ pattern: 'dist/iD.js', included: true },
|
||||
{ pattern: 'dist/iD.css', included: true },
|
||||
{ pattern: 'dist/**/*', included: false },
|
||||
'test/spec/spec_helpers.js',
|
||||
'test/spec/**/*.js'
|
||||
],
|
||||
|
||||
|
||||
// list of files / patterns to exclude
|
||||
exclude: [
|
||||
'**/*.js.map'
|
||||
],
|
||||
|
||||
proxies: {
|
||||
'/dist/': 'http://localhost:9876/base/dist/',
|
||||
'/data/': 'http://localhost:9876/base/dist/data/',
|
||||
'/img/': 'http://localhost:9876/base/dist/img/'
|
||||
},
|
||||
|
||||
// preprocess matching files before serving them to the browser
|
||||
// available preprocessors: https://www.npmjs.com/search?q=keywords:karma-preprocessor
|
||||
preprocessors: {
|
||||
'dist/iD.js': ['coverage']
|
||||
},
|
||||
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: 'dots', 'progress'
|
||||
// available reporters: https://www.npmjs.com/search?q=keywords:karma-reporter
|
||||
reporters: ['progress', 'coverage', 'karma-remap-istanbul'],
|
||||
|
||||
|
||||
// web server port
|
||||
port: 9876,
|
||||
|
||||
|
||||
// enable / disable colors in the output (reporters and logs)
|
||||
colors: true,
|
||||
|
||||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch: true,
|
||||
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
|
||||
browsers: [
|
||||
'ChromeHeadless'
|
||||
],
|
||||
|
||||
|
||||
// Continuous Integration mode
|
||||
// if true, Karma captures browsers, runs the tests and exits
|
||||
singleRun: true,
|
||||
|
||||
// Concurrency level
|
||||
// how many browser instances should be started simultaneously
|
||||
concurrency: Infinity,
|
||||
|
||||
remapIstanbulReporter: {
|
||||
remapOptions: {
|
||||
exclude: [
|
||||
'node_modules'
|
||||
]
|
||||
}, //additional remap options
|
||||
reportOptions: {
|
||||
basePath: 'modules'
|
||||
}, //additional report options
|
||||
reports: {
|
||||
lcovonly: 'coverage/lcof.info',
|
||||
html: 'coverage'
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -110,7 +110,9 @@ export default [
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
...globals.mocha,
|
||||
...globals.jest,
|
||||
'before': 'readonly',
|
||||
'after': 'readonly',
|
||||
'd3': 'readonly',
|
||||
'iD': 'readonly',
|
||||
'sinon': 'readonly',
|
||||
|
||||
@@ -74,8 +74,10 @@ export function coreFileFetcher() {
|
||||
function getUrl(url, which) {
|
||||
let prom = _inflight[url];
|
||||
if (!prom) {
|
||||
_inflight[url] = prom = fetch(url)
|
||||
_inflight[url] = prom = (window.VITEST ? import(`../${url}`) : fetch(url))
|
||||
.then(response => {
|
||||
if (window.VITEST) return response.default;
|
||||
|
||||
if (!response.ok || !response.json) {
|
||||
throw new Error(response.status + ' ' + response.statusText);
|
||||
}
|
||||
|
||||
12
modules/globals.d.ts
vendored
Normal file
12
modules/globals.d.ts
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { FetchMockStatic } from 'fetch-mock';
|
||||
|
||||
declare global {
|
||||
declare var iD: typeof import('.');
|
||||
declare var d3: import('d3');
|
||||
declare var fetchMock: FetchMockStatic;
|
||||
declare var before: typeof beforeEach;
|
||||
declare var after: typeof afterEach;
|
||||
declare var VITEST: true;
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -23,6 +23,9 @@ export * from './validations/index';
|
||||
// This is only done in testing because of the performance penalty.
|
||||
export let debug = false;
|
||||
|
||||
/** @param {boolean} newValue */
|
||||
export const setDebug = (newValue) => { debug = newValue; };
|
||||
|
||||
// Reexport just what our tests use, see #4379
|
||||
import * as D3 from 'd3';
|
||||
export let d3 = {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IntervalTasksQueue } from '../util/IntervalTasksQueue';
|
||||
var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
|
||||
|
||||
// listen for DPI change, e.g. when dragging a browser window from a retina to non-retina screen
|
||||
window.matchMedia(`
|
||||
window.matchMedia?.(`
|
||||
(-webkit-min-device-pixel-ratio: 2), /* Safari */
|
||||
(min-resolution: 2dppx), /* standard */
|
||||
(min-resolution: 192dpi) /* fallback */
|
||||
|
||||
@@ -34,18 +34,9 @@ async function fetchAvailableLayers() {
|
||||
|
||||
const urlForRequest = owsEndpoint + utilQsString(params);
|
||||
const response = await d3_xml(urlForRequest);
|
||||
const xPathSelector = '/wfs:WFS_Capabilities/wfs:FeatureTypeList/wfs:FeatureType/wfs:Name';
|
||||
const regexMatcher = /^vegbilder_1_0:Vegbilder(?<image_type>_360)?_(?<year>\d{4})$/;
|
||||
const NSResolver = response.createNSResolver(response);
|
||||
const l = response.evaluate(
|
||||
xPathSelector,
|
||||
response,
|
||||
NSResolver,
|
||||
XPathResult.ANY_TYPE
|
||||
);
|
||||
let node;
|
||||
const availableLayers = [];
|
||||
while ( (node = l.iterateNext()) !== null ) {
|
||||
for (const node of response.querySelectorAll('FeatureType > Name')) {
|
||||
const match = node.textContent?.match(regexMatcher);
|
||||
if (match) {
|
||||
availableLayers.push({
|
||||
|
||||
@@ -298,7 +298,7 @@ export function uiCombobox(context, klass) {
|
||||
// https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
|
||||
var selected = combo.selectAll('.combobox-option.selected').node();
|
||||
if (selected) {
|
||||
selected.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
selected.scrollIntoView?.({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13451
package-lock.json
generated
13451
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -40,7 +40,7 @@
|
||||
"start:watch": "run-p build:js:watch start:server",
|
||||
"start:server": "node scripts/server.js",
|
||||
"test": "npm-run-all -s lint build test:spec",
|
||||
"test:spec": "karma start config/karma.conf.js",
|
||||
"test:spec": "vitest",
|
||||
"translations": "node scripts/update_locales.js"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -68,6 +68,7 @@
|
||||
"pbf": "^4.0.1",
|
||||
"polygon-clipping": "~0.15.7",
|
||||
"rbush": "4.0.1",
|
||||
"vitest": "^2.0.5",
|
||||
"whatwg-fetch": "^3.6.20",
|
||||
"which-polygon": "2.2.1"
|
||||
},
|
||||
@@ -81,6 +82,11 @@
|
||||
"@rapideditor/mapillary_sprite_source": "^1.8.0",
|
||||
"@rapideditor/temaki": "^5.9.0",
|
||||
"@transifex/api": "^7.1.3",
|
||||
"@types/chai": "^4.3.17",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/happen": "^0.3.0",
|
||||
"@types/sinon": "^17.0.3",
|
||||
"@types/sinon-chai": "^3.2.12",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"browserslist": "^4.23.3",
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
@@ -95,20 +101,15 @@
|
||||
"esbuild": "^0.23.1",
|
||||
"esbuild-visualizer": "^0.6.0",
|
||||
"eslint": "^9.12.0",
|
||||
"fetch-mock": "^9.11.0",
|
||||
"fetch-mock": "^11.1.1",
|
||||
"gaze": "^1.1.3",
|
||||
"glob": "^10.4.5",
|
||||
"happen": "^0.3.2",
|
||||
"js-yaml": "^4.0.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"json-stringify-pretty-compact": "^3.0.0",
|
||||
"karma": "^6.4.4",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-coverage": "2.1.1",
|
||||
"karma-mocha": "^2.0.1",
|
||||
"karma-remap-istanbul": "^0.6.0",
|
||||
"mapillary-js": "4.1.2",
|
||||
"minimist": "^1.2.8",
|
||||
"mocha": "^10.7.3",
|
||||
"name-suggestion-index": "~6.0",
|
||||
"npm-run-all": "^4.0.0",
|
||||
"osm-community-index": "~5.8.1",
|
||||
|
||||
@@ -8,7 +8,7 @@ describe('iD.actionDeleteWay', function() {
|
||||
|
||||
it('removes a way from parent relations', function() {
|
||||
var way = iD.osmWay(),
|
||||
relation = iD.osmRelation({members: [{ id: way.id }, { id: 'w-2' }]}),
|
||||
relation = iD.osmRelation({members: [{ id: way.id }, { id: 'w-99' }]}),
|
||||
action = iD.actionDeleteWay(way.id),
|
||||
graph = iD.coreGraph([way, relation]).update(action),
|
||||
ids = graph.entity(relation.id).members.map(function (m) { return m.id; });
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
describe('iD.behaviorHash', function () {
|
||||
mocha.globals('__onhashchange.hash');
|
||||
|
||||
var hash, context;
|
||||
|
||||
|
||||
@@ -485,6 +485,6 @@ describe('iD.coreDifference', function () {
|
||||
expect(diff.complete()).to.be.ok;
|
||||
});
|
||||
|
||||
it('limits changes to those within a given extent');
|
||||
it.todo('limits changes to those within a given extent');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
describe('iD.modeAddNote', function() {
|
||||
describe.skip('iD.modeAddNote', function() {
|
||||
var context;
|
||||
|
||||
before(function() {
|
||||
|
||||
@@ -589,6 +589,7 @@ describe('iD.osmRelation', function () {
|
||||
});
|
||||
|
||||
describe('#multipolygon', function () {
|
||||
const specify = it;
|
||||
specify('single polygon consisting of a single way', function () {
|
||||
var a = iD.osmNode({loc: [1, 1]});
|
||||
var b = iD.osmNode({loc: [3, 3]});
|
||||
@@ -810,6 +811,7 @@ describe('iD.osmRelation', function () {
|
||||
});
|
||||
|
||||
describe('.creationOrder comparator', function () {
|
||||
const specify = it;
|
||||
specify('orders existing relations newest-first', function () {
|
||||
var a = iD.osmRelation({ id: 'r1' });
|
||||
var b = iD.osmRelation({ id: 'r2' });
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import css from '../../../css/55_cursors.css?raw';
|
||||
|
||||
describe('iD.Map', function() {
|
||||
var content, context, map;
|
||||
|
||||
beforeEach(function() {
|
||||
d3.select('head').append('style').html(css);
|
||||
content = d3.select('body').append('div');
|
||||
context = iD.coreContext().assetPath('../dist/').init().container(content);
|
||||
map = context.map();
|
||||
@@ -164,6 +167,7 @@ describe('iD.Map', function() {
|
||||
return window.getComputedStyle(selection.node()).cursor;
|
||||
}
|
||||
|
||||
const specify = it;
|
||||
specify('points use select-point cursor in browse and select modes', function() {
|
||||
mode.attr('class', 'ideditor mode-browse');
|
||||
expect(cursor(point)).to.match(/cursor-select-point/);
|
||||
|
||||
@@ -163,7 +163,17 @@ describe('maprules', function() {
|
||||
});
|
||||
describe('#clearRules', function() {
|
||||
it('clears _validationRules array', function() {
|
||||
iD.serviceMapRules.clearRules();
|
||||
expect(iD.serviceMapRules.validationRules()).to.be.empty;
|
||||
|
||||
iD.serviceMapRules.addRule({
|
||||
geometry:'node',
|
||||
equals: {amenity:'marketplace'},
|
||||
absence:'name',
|
||||
warning:'\'Marketplace\' preset must be coupled with name'
|
||||
});
|
||||
expect(iD.serviceMapRules.validationRules().length).to.eql(1);
|
||||
|
||||
iD.serviceMapRules.clearRules();
|
||||
expect(iD.serviceMapRules.validationRules()).to.be.empty;
|
||||
});
|
||||
|
||||
@@ -486,9 +486,9 @@ describe('iD.serviceOsm', function () {
|
||||
|
||||
|
||||
describe('#loadMultiple', function () {
|
||||
it('loads nodes');
|
||||
it('loads ways');
|
||||
it('does not ignore repeat requests');
|
||||
it.todo('loads nodes');
|
||||
it.todo('loads ways');
|
||||
it.todo('does not ignore repeat requests');
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('uiCombobox', function() {
|
||||
var start = input.property('selectionStart');
|
||||
var finish = input.property('selectionEnd');
|
||||
|
||||
happen.keydown(input.node(), {keyCode: keyCode});
|
||||
input.node().dispatchEvent(new KeyboardEvent('keydown', { keyCode }));
|
||||
|
||||
switch (key) {
|
||||
case '⇥':
|
||||
@@ -41,23 +41,23 @@ describe('uiCombobox', function() {
|
||||
value = value.substring(0, start - (start === finish ? 1 : 0)) +
|
||||
value.substring(finish, value.length);
|
||||
input.property('value', value);
|
||||
happen.once(input.node(), {type: 'input'});
|
||||
input.node().dispatchEvent(new MouseEvent('input'));
|
||||
break;
|
||||
|
||||
case '⌦':
|
||||
value = value.substring(0, start) +
|
||||
value.substring(finish + (start === finish ? 1 : 0), value.length);
|
||||
input.property('value', value);
|
||||
happen.once(input.node(), {type: 'input'});
|
||||
input.node().dispatchEvent(new MouseEvent('input'));
|
||||
break;
|
||||
|
||||
default:
|
||||
value = value.substring(0, start) + key + value.substring(finish, value.length);
|
||||
input.property('value', value);
|
||||
happen.once(input.node(), {type: 'input'});
|
||||
input.node().dispatchEvent(new MouseEvent('input'));
|
||||
}
|
||||
|
||||
happen.keyup(input.node(), {keyCode: keyCode});
|
||||
input.node().dispatchEvent(new KeyboardEvent('keyup', { keyCode }));
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -178,7 +178,7 @@ describe('uiCombobox', function() {
|
||||
it('does not select when value is empty', function() {
|
||||
input.call(combobox.data(data));
|
||||
focusTypeahead(input);
|
||||
happen.once(input.node(), {type: 'input'});
|
||||
input.node().dispatchEvent(new MouseEvent('input'));
|
||||
expect(body.selectAll('.combobox-option.selected').size()).to.equal(0);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
describe('iD.uiInspector', function () {
|
||||
it.todo('write tests');
|
||||
});
|
||||
|
||||
@@ -1,7 +1,45 @@
|
||||
/* globals chai:false */
|
||||
/* eslint no-extend-native:off */
|
||||
iD.debug = true;
|
||||
import { beforeEach, afterEach, it } from 'vitest';
|
||||
import 'chai';
|
||||
import sinon from 'sinon';
|
||||
import sinonChai from 'sinon-chai';
|
||||
import 'happen';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import envs from '../config/envs.mjs';
|
||||
|
||||
chai.use(sinonChai);
|
||||
|
||||
global.before = beforeEach;
|
||||
global.after = afterEach;
|
||||
global.fetchMock = fetchMock;
|
||||
global.sinon = sinon;
|
||||
global.VITEST = true;
|
||||
|
||||
// create global variables for this data, to match what the esbuild config does
|
||||
for (const [key, value] of Object.entries(envs)) {
|
||||
Reflect.set(global, key, JSON.parse(value));
|
||||
}
|
||||
|
||||
// vitest has deprecated the done() callback, so we overwrite the `it` function
|
||||
const _it = it;
|
||||
Reflect.set(
|
||||
global,
|
||||
'it',
|
||||
Object.assign(
|
||||
(msg: string, fn: (done?: () => void) => void | Promise<void>) => {
|
||||
_it(msg, () =>
|
||||
fn.length ? () => new Promise<void>((resolve) => fn(resolve)) : fn(),
|
||||
);
|
||||
},
|
||||
{ todo: _it.todo, skip: _it.skip },
|
||||
),
|
||||
);
|
||||
|
||||
// must be imported after global envs are defined
|
||||
await import('../modules/id.js');
|
||||
const iD = global.iD;
|
||||
iD.setDebug(true);
|
||||
|
||||
// @ts-expect-error
|
||||
// Disable things that use the network
|
||||
for (var k in iD.services) { delete iD.services[k]; }
|
||||
|
||||
@@ -10,7 +48,7 @@ window.location.hash = '#background=none';
|
||||
|
||||
// Run without data for speed (tests which need data can set it up themselves)
|
||||
iD.fileFetcher.assetPath('../dist/');
|
||||
var cached = iD.fileFetcher.cache();
|
||||
const cached: any = iD.fileFetcher.cache();
|
||||
|
||||
// Initializing `coreContext` will try loading the locale data and English locale strings:
|
||||
cached.locales = { en: { rtl: false, pct: 1 } };
|
||||
@@ -93,24 +131,10 @@ cached.deprecated = [];
|
||||
// Initializing `coreContext` initializes `_uploader`, which tries loading:
|
||||
cached.discarded = {};
|
||||
|
||||
window.d3 = iD.d3; // Remove this if we can avoid exporting all of d3.js
|
||||
|
||||
mocha.setup({
|
||||
timeout: 5000, // 5 sec
|
||||
ui: 'bdd',
|
||||
globals: [
|
||||
'__onmousemove.zoom',
|
||||
'__onmouseup.zoom',
|
||||
'__onkeydown.select',
|
||||
'__onkeyup.select',
|
||||
'__onclick.draw',
|
||||
'__onclick.draw-block'
|
||||
]
|
||||
});
|
||||
|
||||
expect = chai.expect;
|
||||
|
||||
window.d3 = iD.d3; // Remove this if we can avoid exporting all of d3.js
|
||||
delete window.PointerEvent; // force the browser to use mouse events
|
||||
// @ts-expect-error
|
||||
delete window.PointerEvent; // force the browser to use mouse events
|
||||
|
||||
// some sticky fallbacks
|
||||
const capabilities = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"strict": true,
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext", "dom"],
|
||||
"target": "esnext",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"types": ["vitest/globals"]
|
||||
},
|
||||
"include": ["modules", "test"]
|
||||
}
|
||||
11
vitest.config.mts
Normal file
11
vitest.config.mts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
css: true,
|
||||
environment: 'jsdom',
|
||||
globals: true,
|
||||
include: ['test/spec/**/*'],
|
||||
setupFiles: ['./test/spec_helpers.mts'],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user