forked from MapComplete/MapComplete
First steps to a real testing framework: first working version with mocha, chai and doctest-ts
This commit is contained in:
parent
edc366149b
commit
4f4fc650b1
42 changed files with 9032 additions and 9275 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -21,3 +21,4 @@ data/
|
|||
Folder.DotSettings.user
|
||||
index_*.ts
|
||||
.~lock.*
|
||||
*.doctest.ts
|
||||
|
|
|
@ -41,6 +41,12 @@ export class Tag extends TagsFilter {
|
|||
return [`["${this.key}"="${this.value}"]`];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
const t = new Tag("key", "value")
|
||||
t.asHumanString() // => "key=value"
|
||||
t.asHumanString(true) // => "<a href='https://wiki.openstreetmap.org/wiki/Key:key' target='_blank'>key</a>=<a href='https://wiki.openstreetmap.org/wiki/Tag:key%3Dvalue' target='_blank'>value</a>"
|
||||
*/
|
||||
asHumanString(linkToWiki?: boolean, shorten?: boolean, currentProperties?: any) {
|
||||
let v = this.value;
|
||||
if (shorten) {
|
||||
|
|
|
@ -224,6 +224,11 @@ export default class Wikidata {
|
|||
return responses
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 'key' segment from a URL
|
||||
*
|
||||
* Wikidata.ExtractKey("https://www.wikidata.org/wiki/Lexeme:L614072") // => "L614072"
|
||||
*/
|
||||
public static ExtractKey(value: string | number): string {
|
||||
if (typeof value === "number") {
|
||||
return "Q" + value
|
||||
|
|
6
Utils.ts
6
Utils.ts
|
@ -657,6 +657,12 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
return bestColor ?? hex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorders an object: creates a new object where the keys have been added alphabetically
|
||||
*
|
||||
* const sorted = Utils.sortKeys({ x: 'x', abc: {'x': 'x', 'a': 'a'}, def: 'def'})
|
||||
* JSON.stringify(sorted) // => '{"abc":{"a":"a","x":"x"},"def":"def","x":"x"}'
|
||||
*/
|
||||
static sortKeys(o: any) {
|
||||
const copy = {}
|
||||
let keys = Object.keys(o)
|
||||
|
|
|
@ -335,17 +335,24 @@
|
|||
},
|
||||
"deletion": {
|
||||
"softDeletionTags": {
|
||||
"and": ["disused:amenity=bicycle_rental", "bicycle_rental=", "rental="]
|
||||
"and": [
|
||||
"disused:amenity=bicycle_rental",
|
||||
"bicycle_rental=",
|
||||
"rental="
|
||||
]
|
||||
},
|
||||
"neededChangesets": 10,
|
||||
"extraDeleteReasons": [{
|
||||
"extraDeleteReasons": [
|
||||
{
|
||||
"explanation": {
|
||||
"nl": "{title()} is permanent gestopt",
|
||||
"en": "{title()} has closed down permanently"
|
||||
},
|
||||
"changesetMessage": "shop_closed"
|
||||
}],
|
||||
"nonDeleteMappings": [{
|
||||
}
|
||||
],
|
||||
"nonDeleteMappings": [
|
||||
{
|
||||
"if": {
|
||||
"and": [
|
||||
"service:bicycle:rental=no"
|
||||
|
@ -355,6 +362,7 @@
|
|||
"en": "This bicycle shop used to rent out bikes but doesn't rent out bikes anymore",
|
||||
"nl": "Deze fietszaak verhuurde vroeger fietsen, maar nu niet meer"
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -200,13 +200,15 @@
|
|||
"disused:amenity:={amenity}"
|
||||
]
|
||||
},
|
||||
"extraDeleteReasons": [{
|
||||
"extraDeleteReasons": [
|
||||
{
|
||||
"explanation": {
|
||||
"nl": "{title()} is permanent gestopt",
|
||||
"en": "{title()} has closed down permanently"
|
||||
},
|
||||
"changesetMessage": "shop_closed"
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
"allowMove": true,
|
||||
"mapRendering": [
|
||||
|
|
|
@ -672,13 +672,15 @@
|
|||
"disused:amenity:={amenity}"
|
||||
]
|
||||
},
|
||||
"extraDeleteReasons": [{
|
||||
"extraDeleteReasons": [
|
||||
{
|
||||
"explanation": {
|
||||
"nl": "{title()} is permanent gestopt",
|
||||
"en": "{title()} has closed down permanently"
|
||||
},
|
||||
"changesetMessage": "shop_closed"
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
"allowMove": true,
|
||||
"mapRendering": [
|
||||
|
|
|
@ -357,13 +357,15 @@
|
|||
"disused:amenity:={amenity}"
|
||||
]
|
||||
},
|
||||
"extraDeleteReasons": [{
|
||||
"extraDeleteReasons": [
|
||||
{
|
||||
"explanation": {
|
||||
"nl": "{title()} is permanent gestopt",
|
||||
"en": "{title()} has closed down permanently"
|
||||
},
|
||||
"changesetMessage": "shop_closed"
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
"allowMove": true,
|
||||
"mapRendering": [
|
||||
|
|
|
@ -838,7 +838,8 @@
|
|||
"zh_Hant": "位於地下一樓",
|
||||
"de": "Ist im 1. Untergeschoss",
|
||||
"hu": "Az első alagsori szinten",
|
||||
"id": "Terletak di lantai basement pertama"
|
||||
"id": "Terletak di lantai basement pertama",
|
||||
"fr": "Sous-sol"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -523,6 +523,18 @@
|
|||
"splitTitle": "Choose on the map where to split this road"
|
||||
},
|
||||
"validation": {
|
||||
"color": {
|
||||
"description": "A color or hexcode"
|
||||
},
|
||||
"date": {
|
||||
"description": "A date, starting with the year"
|
||||
},
|
||||
"decimal": {
|
||||
"description": "A number"
|
||||
},
|
||||
"direction": {
|
||||
"description": "An orientation"
|
||||
},
|
||||
"email": {
|
||||
"description": "email-adres",
|
||||
"feedback": "This is not a valid email address",
|
||||
|
@ -541,6 +553,9 @@
|
|||
"mustBeWhole": "Only whole numbers are allowed",
|
||||
"notANumber": "Enter a number"
|
||||
},
|
||||
"opening_hours": {
|
||||
"description": "Opening hours"
|
||||
},
|
||||
"pfloat": {
|
||||
"description": "a positive number"
|
||||
},
|
||||
|
@ -555,10 +570,16 @@
|
|||
"string": {
|
||||
"description": "a piece of text"
|
||||
},
|
||||
"text": {
|
||||
"description": "a piece of text"
|
||||
},
|
||||
"tooLong": "Text is to long, at most 255 characters are allowed. You do have {count} characters now",
|
||||
"url": {
|
||||
"description": "link to a website",
|
||||
"feedback": "This is not a valid web address"
|
||||
},
|
||||
"wikidata": {
|
||||
"description": "A Wikidata identifier"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -494,6 +494,9 @@
|
|||
},
|
||||
"5": {
|
||||
"then": "Tandem bicycles can be rented here"
|
||||
},
|
||||
"6": {
|
||||
"then": "Race bicycles can be rented here"
|
||||
}
|
||||
},
|
||||
"question": "What kind of bicycles and accessories are rented here?",
|
||||
|
|
|
@ -494,6 +494,9 @@
|
|||
},
|
||||
"5": {
|
||||
"then": "Tandems kunnen hier gehuurd worden"
|
||||
},
|
||||
"6": {
|
||||
"then": "Wielerfietsen (sportfietsen) kunnen hier gehuurd worden"
|
||||
}
|
||||
},
|
||||
"question": "Wat voor soort fietsen en fietstoebehren worden hier verhuurd?",
|
||||
|
|
1413
package-lock.json
generated
1413
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -12,7 +12,8 @@
|
|||
"strttest": "export NODE_OPTIONS=--max_old_space_size=8364 && parcel serve test.html",
|
||||
"watch:css": "tailwindcss -i index.css -o css/index-tailwind-output.css --watch",
|
||||
"generate:css": "tailwindcss -i index.css -o css/index-tailwind-output.css",
|
||||
"test": "ts-node test/TestAll.ts",
|
||||
"generate:doctests": "doctest-ts --mocha Logic/**/*.ts && doctest-ts --mocha UI/**/*.ts && doctest-ts --mocha *.ts && doctest-ts --mocha Models/**/*.ts",
|
||||
"test": "(npm run generate:doctests 2>&1 | grep -v \"No doctests found in\") && mocha --require ts-node/register \"Logic/**/*.doctest.ts\" \"tests/*\" \"tests/**/*.ts\"",
|
||||
"init": "npm ci && npm run generate && npm run generate:editor-layer-index && npm run generate:layouts && npm run clean",
|
||||
"add-weblate-upstream": "git remote add weblate-layers https://hosted.weblate.org/git/mapcomplete/layer-translations/ ; git remote add weblate-core https://hosted.weblate.org/git/mapcomplete/layer-core/; git remote add weblate-themes https://hosted.weblate.org/git/mapcomplete/layer-themes/; git remote add weblate-github git@github.com:weblate/MapComplete.git",
|
||||
"fix-weblate": "git remote update weblate-layers; git merge weblate-layers/master",
|
||||
|
@ -41,7 +42,7 @@
|
|||
"prepare-deploy": "./scripts/build.sh",
|
||||
"gittag": "ts-node scripts/printVersion.ts | bash",
|
||||
"lint": "tslint --project . -c tslint.json '**.ts' ",
|
||||
"clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(404\\|index\\|land\\|test\\|preferences\\|customGenerator\\|professional\\|automaton\\|import_helper\\|import_viewer\\|theme\\).html\" | xargs rm) && (ls | grep \"^index_[a-zA-Z_]\\+\\.ts$\" | xargs rm) && (ls | grep \".*.webmanifest$\" | xargs rm)",
|
||||
"clean": "rm -rf .cache/ && (find . -type f -name \"*.doctest.ts\" | xargs rm) && (find *.html | grep -v \"\\(404\\|index\\|land\\|test\\|preferences\\|customGenerator\\|professional\\|automaton\\|import_helper\\|import_viewer\\|theme\\).html\" | xargs rm) && (ls | grep \"^index_[a-zA-Z_]\\+\\.ts$\" | xargs rm) && (ls | grep \".*.webmanifest$\" | xargs rm)",
|
||||
"generate:dependency-graph": "node_modules/.bin/depcruise --exclude \"^node_modules\" --output-type dot Logic/State/MapState.ts > dependencies.dot && dot dependencies.dot -T svg -o dependencies.svg && rm dependencies.dot",
|
||||
"script": "ts-node"
|
||||
},
|
||||
|
@ -58,15 +59,18 @@
|
|||
"@turf/distance": "^6.5.0",
|
||||
"@turf/length": "^6.5.0",
|
||||
"@turf/turf": "^6.5.0",
|
||||
"@types/chai": "^4.3.0",
|
||||
"@types/jquery": "^3.5.5",
|
||||
"@types/leaflet-markercluster": "^1.0.3",
|
||||
"@types/leaflet-providers": "^1.2.0",
|
||||
"@types/lz-string": "^1.3.34",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/papaparse": "^5.3.1",
|
||||
"@types/prompt-sync": "^4.1.0",
|
||||
"@types/wikidata-sdk": "^6.1.0",
|
||||
"@types/xml2js": "^0.4.9",
|
||||
"country-language": "^0.1.7",
|
||||
"doctest-ts": "^0.5.0",
|
||||
"email-validator": "^2.0.4",
|
||||
"escape-html": "^1.0.3",
|
||||
"i18next-client": "^1.11.4",
|
||||
|
@ -101,8 +105,10 @@
|
|||
"@babel/polyfill": "^7.10.4",
|
||||
"@types/node": "^7.0.5",
|
||||
"assert": "^2.0.0",
|
||||
"chai": "^4.3.6",
|
||||
"dependency-cruiser": "^10.4.0",
|
||||
"fs": "0.0.1-security",
|
||||
"mocha": "^9.2.2",
|
||||
"read-file": "^0.2.0",
|
||||
"sharp": "^0.28.3",
|
||||
"ts-node": "^9.0.0",
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
import T from "./TestHelper";
|
||||
import ValidatedTextField from "../UI/Input/ValidatedTextField";
|
||||
import Translations from "../UI/i18n/Translations";
|
||||
|
||||
export default class ValidatedTextFieldTranslationsSpec extends T {
|
||||
constructor() {
|
||||
super([
|
||||
["Test all", () => {
|
||||
const ts = Translations.t.validation;
|
||||
console.log("Hello world!")
|
||||
const allErrors = Array.from(ValidatedTextField.allTypes.keys()).map(key => {
|
||||
const errors = []
|
||||
const t = ts[key]
|
||||
if (t === undefined) {
|
||||
errors.push("No tranlations at all for " + key)
|
||||
}
|
||||
return errors;
|
||||
})
|
||||
const errs = [].concat(...allErrors)
|
||||
if (errs.length > 0) {
|
||||
errs.forEach(e => console.log(e))
|
||||
// throw errs.join("\n")
|
||||
}
|
||||
}]
|
||||
]);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -10,18 +10,15 @@ import RelationSplitHandlerSpec from "./RelationSplitHandler.spec";
|
|||
import SplitActionSpec from "./SplitAction.spec";
|
||||
import {Utils} from "../Utils";
|
||||
import TileFreshnessCalculatorSpec from "./TileFreshnessCalculator.spec";
|
||||
import WikidataSpecTest from "./Wikidata.spec.test";
|
||||
import ImageProviderSpec from "./ImageProvider.spec";
|
||||
import ActorsSpec from "./Actors.spec";
|
||||
import ReplaceGeometrySpec from "./ReplaceGeometry.spec";
|
||||
import LegacyThemeLoaderSpec from "./LegacyThemeLoader.spec";
|
||||
import T from "./TestHelper";
|
||||
import CreateNoteImportLayerSpec from "./CreateNoteImportLayer.spec";
|
||||
import ValidatedTextFieldTranslationsSpec from "./ValidatedTextFieldTranslations.spec";
|
||||
import CreateCacheSpec from "./CreateCache.spec";
|
||||
import CodeQualitySpec from "./CodeQuality.spec";
|
||||
import ImportMultiPolygonSpec from "./ImportMultiPolygon.spec";
|
||||
import {ChangesetHandler} from "../Logic/Osm/ChangesetHandler";
|
||||
import ChangesetHandlerSpec from "./ChangesetHandler.spec";
|
||||
import ChangesSpec from "./Changes.spec";
|
||||
|
||||
|
@ -41,13 +38,11 @@ async function main() {
|
|||
new RelationSplitHandlerSpec(),
|
||||
new SplitActionSpec(),
|
||||
new TileFreshnessCalculatorSpec(),
|
||||
new WikidataSpecTest(),
|
||||
new ImageProviderSpec(),
|
||||
new ActorsSpec(),
|
||||
new ReplaceGeometrySpec(),
|
||||
new LegacyThemeLoaderSpec(),
|
||||
new CreateNoteImportLayerSpec(),
|
||||
new ValidatedTextFieldTranslationsSpec(),
|
||||
new CreateCacheSpec(),
|
||||
new CodeQualitySpec(),
|
||||
new ImportMultiPolygonSpec(),
|
15
tests/Chai.spec.ts
Normal file
15
tests/Chai.spec.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {describe} from 'mocha'
|
||||
import {expect} from 'chai'
|
||||
|
||||
describe("TestSuite", () => {
|
||||
|
||||
describe("function onder test", () => {
|
||||
it("should work", () => {
|
||||
expect("abc").eq("abc")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it("global test", () => {
|
||||
expect("abc").eq("abc")
|
||||
})
|
7499
tests/Logic/Web/Wikidata.spec.ts
Normal file
7499
tests/Logic/Web/Wikidata.spec.ts
Normal file
File diff suppressed because it is too large
Load diff
14
tests/UI/ValidatedTextFieldTranslations.ts
Normal file
14
tests/UI/ValidatedTextFieldTranslations.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import {describe} from 'mocha'
|
||||
import {expect} from 'chai'
|
||||
import Translations from "../../UI/i18n/Translations";
|
||||
import ValidatedTextField from "../../UI/Input/ValidatedTextField";
|
||||
|
||||
describe("ValidatedTextFields", () => {
|
||||
|
||||
it("All validated text fields should have a name and description", () => {
|
||||
const ts = Translations.t.validation;
|
||||
const missingTranslations = Array.from(ValidatedTextField.allTypes.keys())
|
||||
.filter(key => ts[key] === undefined || ts[key].description === undefined)
|
||||
expect(missingTranslations, "These validated text fields don't have a type name defined in en.json. (Did you just add one? Run `npm run generate:translations`)").to.be.empty
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue