Fix #343, add the poss^Cility to use the test backend (WIP), improve testability of OsmConnection (WIP)

This commit is contained in:
Pieter Vander Vennet 2021-06-08 16:52:31 +02:00
parent 8d404b1ba9
commit 9458128ccf
7 changed files with 138 additions and 42 deletions

View file

@ -7,6 +7,7 @@ import {ElementStorage} from "../ElementStorage";
import Svg from "../../Svg"; import Svg from "../../Svg";
import LayoutConfig from "../../Customizations/JSON/LayoutConfig"; import LayoutConfig from "../../Customizations/JSON/LayoutConfig";
import Img from "../../UI/Base/Img"; import Img from "../../UI/Base/Img";
import {Utils} from "../../Utils";
export default class UserDetails { export default class UserDetails {
@ -22,28 +23,49 @@ export default class UserDetails {
export class OsmConnection { export class OsmConnection {
public static readonly _oauth_configs = {
"osm": {
oauth_consumer_key: 'hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem',
oauth_secret: 'wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI',
url: "https://openstreetmap.org"
},
"osm-test": {
oauth_consumer_key: 'Zgr7EoKb93uwPv2EOFkIlf3n9NLwj5wbyfjZMhz2',
oauth_secret: '3am1i1sykHDMZ66SGq4wI2Z7cJMKgzneCHp3nctn',
url: "https://master.apis.dev.openstreetmap.org"
}
}
public auth; public auth;
public userDetails: UIEventSource<UserDetails>; public userDetails: UIEventSource<UserDetails>;
_dryRun: boolean; _dryRun: boolean;
public preferencesHandler: OsmPreferences; public preferencesHandler: OsmPreferences;
public changesetHandler: ChangesetHandler; public changesetHandler: ChangesetHandler;
private _onLoggedIn: ((userDetails: UserDetails) => void)[] = []; private _onLoggedIn: ((userDetails: UserDetails) => void)[] = [];
private readonly _iframeMode: Boolean | boolean; private readonly _iframeMode: Boolean | boolean;
private readonly _singlePage: boolean; private readonly _singlePage: boolean;
private readonly _oauth_config: {
oauth_consumer_key: string,
oauth_secret: string,
url: string
};
constructor(dryRun: boolean, oauth_token: UIEventSource<string>, constructor(dryRun: boolean, oauth_token: UIEventSource<string>,
// Used to keep multiple changesets open and to write to the correct changeset // Used to keep multiple changesets open and to write to the correct changeset
layoutName: string, layoutName: string,
singlePage: boolean = true) { singlePage: boolean = true,
osmConfiguration: "osm" | "osm-test" = 'osm'
) {
this._singlePage = singlePage; this._singlePage = singlePage;
this._iframeMode = window !== window.top; this._oauth_config = OsmConnection._oauth_configs[osmConfiguration] ?? OsmConnection._oauth_configs.osm;
console.debug("Using backend", this._oauth_config.url)
this._iframeMode = Utils.runningFromConsole ? false : window !== window.top;
this.userDetails = new UIEventSource<UserDetails>(new UserDetails(), "userDetails"); this.userDetails = new UIEventSource<UserDetails>(new UserDetails(), "userDetails");
this.userDetails.data.dryRun = dryRun; this.userDetails.data.dryRun = dryRun;
this._dryRun = dryRun; this._dryRun = dryRun;
this.updateAuthObject(); this.updateAuthObject();
this.preferencesHandler = new OsmPreferences(this.auth, this); this.preferencesHandler = new OsmPreferences(this.auth, this);
@ -67,37 +89,6 @@ export class OsmConnection {
console.log("Not authenticated"); console.log("Not authenticated");
} }
} }
private updateAuthObject(){
let pwaStandAloneMode = false;
try {
if (window.matchMedia('(display-mode: standalone)').matches || window.matchMedia('(display-mode: fullscreen)').matches) {
pwaStandAloneMode = true;
}
} catch (e) {
console.warn("Detecting standalone mode failed", e, ". Assuming in browser and not worrying furhter")
}
if (this._iframeMode || pwaStandAloneMode || !this._singlePage) {
// In standalone mode, we DON'T use single page login, as 'redirecting' opens a new window anyway...
// Same for an iframe...
this.auth = new osmAuth({
oauth_consumer_key: 'hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem',
oauth_secret: 'wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI',
singlepage: false,
auto: true,
});
} else {
this.auth = new osmAuth({
oauth_consumer_key: 'hivV7ec2o49Two8g9h8Is1VIiVOgxQ1iYexCbvem',
oauth_secret: 'wDBRTCem0vxD7txrg1y6p5r8nvmz8tAhET7zDASI',
singlepage: true,
landing: window.location.href,
auto: true,
});
}
}
public UploadChangeset( public UploadChangeset(
layout: LayoutConfig, layout: LayoutConfig,
@ -144,7 +135,7 @@ export class OsmConnection {
// Not authorized - our token probably got revoked // Not authorized - our token probably got revoked
// Reset all the tokens // Reset all the tokens
const tokens = [ const tokens = [
"https://www.openstreetmap.orgoauth_request_token_secret", "https://www.openstreetmap.orgoauth_request_token_secret",
"https://www.openstreetmap.orgoauth_token", "https://www.openstreetmap.orgoauth_token",
"https://www.openstreetmap.orgoauth_token_secret"] "https://www.openstreetmap.orgoauth_token_secret"]
tokens.forEach(token => localStorage.removeItem(token)) tokens.forEach(token => localStorage.removeItem(token))
@ -196,6 +187,33 @@ export class OsmConnection {
}); });
} }
private updateAuthObject() {
let pwaStandAloneMode = false;
try {
if (Utils.runningFromConsole) {
pwaStandAloneMode = true
} else if (window.matchMedia('(display-mode: standalone)').matches || window.matchMedia('(display-mode: fullscreen)').matches) {
pwaStandAloneMode = true;
}
} catch (e) {
console.warn("Detecting standalone mode failed", e, ". Assuming in browser and not worrying furhter")
}
const standalone = this._iframeMode || pwaStandAloneMode || !this._singlePage;
// In standalone mode, we DON'T use single page login, as 'redirecting' opens a new window anyway...
// Same for an iframe...
this.auth = new osmAuth({
oauth_consumer_key: this._oauth_config.oauth_consumer_key,
oauth_secret: this._oauth_config.oauth_secret,
url: this._oauth_config.url,
landing: standalone ? undefined : window.location.href,
singlepage: !standalone,
auto: true,
});
}
private CheckForMessagesContinuously() { private CheckForMessagesContinuously() {
const self = this; const self = this;

View file

@ -96,10 +96,13 @@ export class OsmPreferences {
} }
public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> { public GetPreference(key: string, prefix: string = "mapcomplete-"): UIEventSource<string> {
console.warn(key)
key = prefix + key; key = prefix + key;
key = key.replace(/[:\\\/"' {}.%]/g, '')
if (key.length >= 255) { if (key.length >= 255) {
throw "Preferences: key length to big"; throw "Preferences: key length to big";
} }
console.warn(key)
if (this.preferenceSources[key] !== undefined) { if (this.preferenceSources[key] !== undefined) {
return this.preferenceSources[key]; return this.preferenceSources[key];
} }

View file

@ -98,6 +98,7 @@ export default class State {
public readonly featureSwitchIsTesting: UIEventSource<boolean>; public readonly featureSwitchIsTesting: UIEventSource<boolean>;
public readonly featureSwitchIsDebugging: UIEventSource<boolean>; public readonly featureSwitchIsDebugging: UIEventSource<boolean>;
public readonly featureSwitchShowAllQuestions: UIEventSource<boolean>; public readonly featureSwitchShowAllQuestions: UIEventSource<boolean>;
public readonly featureSwitchApiURL: UIEventSource<string>;
/** /**
@ -201,7 +202,6 @@ export default class State {
this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false,
"Always show all questions"); "Always show all questions");
this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false", this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false",
"If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org") "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org")
.map(str => str === "true", [], b => "" + b); .map(str => str === "true", [], b => "" + b);
@ -209,6 +209,10 @@ export default class State {
this.featureSwitchIsDebugging = QueryParameters.GetQueryParameter("debug","false", this.featureSwitchIsDebugging = QueryParameters.GetQueryParameter("debug","false",
"If true, shows some extra debugging help such as all the available tags on every object") "If true, shows some extra debugging help such as all the available tags on every object")
.map(str => str === "true", [], b => "" + b) .map(str => str === "true", [], b => "" + b)
this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend","https://openstreetmap.org",
"The OSM backend to use - can be used to redirect mapcomplete to a testing backend or e.g. openHistoricalMap")
} }
@ -217,7 +221,9 @@ export default class State {
QueryParameters.GetQueryParameter("oauth_token", undefined, QueryParameters.GetQueryParameter("oauth_token", undefined,
"Used to complete the login"), "Used to complete the login"),
layoutToUse?.id, layoutToUse?.id,
true true,
// @ts-ignore
this.featureSwitchApiURL.data
); );

View file

@ -1,3 +1,4 @@
import ValidatedTextField from "./UI/Input/ValidatedTextField"; import ValidatedTextField from "./UI/Input/ValidatedTextField";
import TestAll from "./test/TestAll";
ValidatedTextField.InputForType("phone").AttachTo("maindiv") new TestAll().testAll();

View file

@ -0,0 +1,46 @@
import T from "./TestHelper";
import UserDetails, {OsmConnection} from "../Logic/Osm/OsmConnection";
import {UIEventSource} from "../Logic/UIEventSource";
import ScriptUtils from "../scripts/ScriptUtils";
export default class OsmConnectionSpec extends T {
/*
This token gives access to the TESTING-instance of OSM. No real harm can be done with it, so it can be commited to the repo
*/
private static _osm_token = "LJFmv2nUicSNmBNsFeyCHx5KKx6Aiesx8pXPbX4n"
constructor() {
super("OsmConnectionSpec-test", [
["login on dev",
() => {
const osmConn = new OsmConnection(false,
new UIEventSource<string>(undefined),
"Unit test",
true,
"osm-test"
)
osmConn.userDetails.map((userdetails : UserDetails) => {
if(userdetails.loggedIn){
console.log("Logged in with the testing account. Writing some random data to test preferences")
const data = Math.random().toString()
osmConn.GetPreference("test").setData(data)
osmConn.GetPreference("https://raw.githubusercontent.com/AgusQui/MapCompleteRailway/main/railway")
.setData(data)
}
});
ScriptUtils.sleep(1000)
}
]
]);
}
}

View file

@ -9,7 +9,26 @@ import TagQuestionSpec from "./TagQuestion.spec";
import ImageSearcherSpec from "./ImageSearcher.spec"; import ImageSearcherSpec from "./ImageSearcher.spec";
import ThemeSpec from "./Theme.spec"; import ThemeSpec from "./Theme.spec";
import UtilsSpec from "./Utils.spec"; import UtilsSpec from "./Utils.spec";
import OsmConnectionSpec from "./OsmConnection.spec";
import T from "./TestHelper";
import {FixedUiElement} from "../UI/Base/FixedUiElement";
import Combine from "../UI/Base/Combine";
export default class TestAll {
private needsBrowserTests: T[] = [new OsmConnectionSpec()]
public testAll(): void {
Utils.runningFromConsole = false
for (const test of this.needsBrowserTests.concat(allTests)) {
if (test.failures.length > 0) {
new Combine([new FixedUiElement("TEST FAILED: " + test.name).SetStyle("background: red"),
...test.failures])
.AttachTo("maindiv")
throw "Some test failed"
}
}
}
}
const allTests = [ const allTests = [
new TagSpec(), new TagSpec(),
@ -20,8 +39,9 @@ const allTests = [
new ThemeSpec(), new ThemeSpec(),
new UtilsSpec()] new UtilsSpec()]
for (const test of allTests) { for (const test of allTests) {
if(test.failures.length > 0){ if (test.failures.length > 0) {
throw "Some test failed" throw "Some test failed"
} }
} }

View file

@ -1,8 +1,10 @@
export default class T { export default class T {
public readonly failures = [] public readonly failures : string[] = []
public readonly name : string;
constructor(testsuite: string, tests: [string, () => void][]) { constructor(testsuite: string, tests: [string, () => void][]) {
this.name = testsuite
for (const [name, test] of tests) { for (const [name, test] of tests) {
try { try {
test(); test();