mirror of
https://github.com/a-nyx/maputnik-with-pmtiles.git
synced 2025-01-30 23:15:28 +01:00
Merge pull request #280 from orangemug/fix/web-driver-tests-v8
Improved tests
This commit is contained in:
commit
f0147cc89a
57 changed files with 6387 additions and 3138 deletions
11
.babelrc
11
.babelrc
|
@ -1,4 +1,13 @@
|
||||||
{
|
{
|
||||||
"presets": ["env", "react"],
|
"presets": ["env", "react"],
|
||||||
"plugins": ["transform-object-rest-spread", "transform-class-properties"]
|
"plugins": ["transform-object-rest-spread", "transform-class-properties"],
|
||||||
|
"env": {
|
||||||
|
"test": {
|
||||||
|
"plugins": [
|
||||||
|
["istanbul", {
|
||||||
|
exclude: ["node_modules/**", "test/**"]
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
84
.circleci/config.yml
Normal file
84
.circleci/config.yml
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
version: 2
|
||||||
|
templates:
|
||||||
|
# Test the build **only** no webdriver
|
||||||
|
build-steps: &build-steps
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: "Create artifacts directory"
|
||||||
|
command: mkdir /tmp/artifacts
|
||||||
|
- restore_cache:
|
||||||
|
key: v1-dependencies-{{ checksum "package.json" }}
|
||||||
|
|
||||||
|
- run: npm install
|
||||||
|
|
||||||
|
- save_cache:
|
||||||
|
paths:
|
||||||
|
- node_modules
|
||||||
|
key: v1-dependencies-{{ checksum "package.json" }}
|
||||||
|
|
||||||
|
- run: mkdir -p /tmp/artifacts/logs
|
||||||
|
- run: npm run build
|
||||||
|
- run: npm run lint
|
||||||
|
- run: npm run lint-styles
|
||||||
|
- store_artifacts:
|
||||||
|
path: /tmp/artifacts
|
||||||
|
destination: /artifacts
|
||||||
|
# Test in webdriver
|
||||||
|
wdio-steps: &wdio-steps
|
||||||
|
- checkout
|
||||||
|
- run:
|
||||||
|
name: "Create artifacts directory"
|
||||||
|
command: mkdir /tmp/artifacts
|
||||||
|
- restore_cache:
|
||||||
|
key: v1-dependencies-{{ checksum "package.json" }}
|
||||||
|
|
||||||
|
- run: npm install
|
||||||
|
|
||||||
|
- save_cache:
|
||||||
|
paths:
|
||||||
|
- node_modules
|
||||||
|
key: v1-dependencies-{{ checksum "package.json" }}
|
||||||
|
|
||||||
|
- run: mkdir -p /tmp/artifacts/logs
|
||||||
|
- run: npm run build
|
||||||
|
- run: npm run lint
|
||||||
|
- run: npm run lint-styles
|
||||||
|
- run: DOCKER_HOST=localhost npm test
|
||||||
|
- run: ./node_modules/.bin/istanbul report --include /tmp/artifacts/coverage/coverage.json --dir /tmp/artifacts/coverage html lcov
|
||||||
|
- store_artifacts:
|
||||||
|
path: /tmp/artifacts
|
||||||
|
destination: /artifacts
|
||||||
|
jobs:
|
||||||
|
build-linux-node-v6:
|
||||||
|
docker:
|
||||||
|
- image: node:6
|
||||||
|
working_directory: ~/repo-linux-node-v6
|
||||||
|
steps: *build-steps
|
||||||
|
build-linux-node-v8:
|
||||||
|
docker:
|
||||||
|
- image: node:8
|
||||||
|
- image: selenium/standalone-chrome:3.8.1
|
||||||
|
working_directory: ~/repo-linux-node-v8
|
||||||
|
steps: *wdio-steps
|
||||||
|
build-linux-node-v9:
|
||||||
|
docker:
|
||||||
|
- image: node:9
|
||||||
|
working_directory: ~/repo-linux-node-v9
|
||||||
|
steps: *build-steps
|
||||||
|
build-osx-node-v9:
|
||||||
|
macos:
|
||||||
|
xcode: "9.0"
|
||||||
|
dependencies:
|
||||||
|
override:
|
||||||
|
- brew install node@9
|
||||||
|
working_directory: ~/repo-linux-node-v9
|
||||||
|
steps: *build-steps
|
||||||
|
|
||||||
|
workflows:
|
||||||
|
version: 2
|
||||||
|
build:
|
||||||
|
jobs:
|
||||||
|
- build-linux-node-v6
|
||||||
|
- build-linux-node-v8
|
||||||
|
- build-linux-node-v9
|
||||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -30,3 +30,6 @@ node_modules
|
||||||
|
|
||||||
# Ignore build files
|
# Ignore build files
|
||||||
public
|
public
|
||||||
|
/errorShots
|
||||||
|
/old
|
||||||
|
/build
|
||||||
|
|
19
.travis.yml
19
.travis.yml
|
@ -1,30 +1,12 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
addons:
|
|
||||||
firefox: latest
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: linux
|
|
||||||
node_js: "6"
|
|
||||||
- os: linux
|
|
||||||
env: CXX=g++-4.8
|
|
||||||
node_js: "7"
|
|
||||||
- os: linux
|
|
||||||
node_js: "8"
|
|
||||||
- os: linux
|
|
||||||
env: CXX=g++-4.8
|
|
||||||
node_js: "9"
|
|
||||||
- os: osx
|
- os: osx
|
||||||
node_js: "6"
|
node_js: "6"
|
||||||
- os: osx
|
|
||||||
node_js: "7"
|
|
||||||
- os: osx
|
- os: osx
|
||||||
node_js: "8"
|
node_js: "8"
|
||||||
- os: osx
|
- os: osx
|
||||||
node_js: "9"
|
node_js: "9"
|
||||||
before_install:
|
|
||||||
- export CHROME_BIN=chromium-browser
|
|
||||||
- export DISPLAY=:99.0
|
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh -e /etc/init.d/xvfb start; fi
|
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
script:
|
script:
|
||||||
|
@ -32,7 +14,6 @@ script:
|
||||||
- node --stack_size=100000 $(which npm) run build
|
- node --stack_size=100000 $(which npm) run build
|
||||||
- npm run lint
|
- npm run lint
|
||||||
- npm run lint-styles
|
- npm run lint-styles
|
||||||
- npm run test
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
|
|
27
README.md
27
README.md
|
@ -68,6 +68,33 @@ npm run lint
|
||||||
npm run lint-styles
|
npm run lint-styles
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
For testing we use [webdriverio](http://webdriver.io) and [selenium-standalone](https://github.com/vvo/selenium-standalone)
|
||||||
|
|
||||||
|
[selenium-standalone](https://github.com/vvo/selenium-standalone) starts a server that will launch browsers on your local machine. We use chrome so you **must** have chrome installed on your machine.
|
||||||
|
|
||||||
|
Now open and terminal and run the following. This will install the drivers on your local machine
|
||||||
|
|
||||||
|
```
|
||||||
|
./node_modules/.bin/selenium-standalone install
|
||||||
|
```
|
||||||
|
|
||||||
|
Now start the standalone server
|
||||||
|
|
||||||
|
```
|
||||||
|
./node_modules/.bin/selenium-standalone start
|
||||||
|
```
|
||||||
|
|
||||||
|
Then open another terminal and run
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
After some time you should see a browser launch which will be automated by the test runner.
|
||||||
|
|
||||||
|
|
||||||
## Related Projects
|
## Related Projects
|
||||||
|
|
||||||
- [maputnik-dev-server](https://github.com/nycplanning/labs-maputnik-dev-server) - An express.js server that allows for quickly loading the style from any mapboxGL map into mapuntnik.
|
- [maputnik-dev-server](https://github.com/nycplanning/labs-maputnik-dev-server) - An express.js server that allows for quickly loading the style from any mapboxGL map into mapuntnik.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- nodejs_version: "6"
|
- nodejs_version: "6"
|
||||||
- nodejs_version: "7"
|
|
||||||
- nodejs_version: "8"
|
- nodejs_version: "8"
|
||||||
- nodejs_version: "9"
|
- nodejs_version: "9"
|
||||||
platform:
|
platform:
|
||||||
|
@ -16,4 +15,3 @@ build_script:
|
||||||
- npm run build
|
- npm run build
|
||||||
test_script:
|
test_script:
|
||||||
- npm run lint
|
- npm run lint
|
||||||
- npm test
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
machine:
|
|
||||||
node:
|
|
||||||
version: 6
|
|
||||||
test:
|
|
||||||
post:
|
|
||||||
- npm run build
|
|
|
@ -1,48 +1,62 @@
|
||||||
var webpack = require("webpack");
|
var webpack = require("webpack");
|
||||||
var WebpackDevServer = require("webpack-dev-server");
|
var WebpackDevServer = require("webpack-dev-server");
|
||||||
var webpackConfig = require("./webpack.production.config");
|
var webpackConfig = require("./webpack.config");
|
||||||
var testConfig = require("../test/config/specs");
|
var testConfig = require("../test/config/specs");
|
||||||
|
var artifacts = require("../test/artifacts");
|
||||||
|
var isDocker = require("is-docker");
|
||||||
|
|
||||||
|
|
||||||
var server;
|
var server;
|
||||||
|
var SCREENSHOT_PATH = artifacts.pathSync("screenshots");
|
||||||
|
|
||||||
exports.config = {
|
exports.config = {
|
||||||
specs: [
|
specs: [
|
||||||
'./test/specs/**/*.js'
|
'./test/functional/index.js'
|
||||||
],
|
],
|
||||||
exclude: [
|
exclude: [
|
||||||
],
|
],
|
||||||
maxInstances: 10,
|
maxInstances: 10,
|
||||||
capabilities: [{
|
capabilities: [{
|
||||||
maxInstances: 5,
|
maxInstances: 5,
|
||||||
browserName: 'firefox'
|
browserName: 'chrome'
|
||||||
}],
|
}],
|
||||||
sync: true,
|
sync: true,
|
||||||
logLevel: 'verbose',
|
logLevel: 'verbose',
|
||||||
coloredLogs: true,
|
coloredLogs: true,
|
||||||
bail: 0,
|
bail: 0,
|
||||||
screenshotPath: './errorShots/',
|
screenshotPath: SCREENSHOT_PATH,
|
||||||
|
// Note: This is here because @orangemug currently runs Maputnik inside a docker container.
|
||||||
|
host: process.env.DOCKER_HOST || "0.0.0.0",
|
||||||
baseUrl: 'http://localhost',
|
baseUrl: 'http://localhost',
|
||||||
waitforTimeout: 10000,
|
waitforTimeout: 10000,
|
||||||
connectionRetryTimeout: 90000,
|
connectionRetryTimeout: 90000,
|
||||||
connectionRetryCount: 3,
|
connectionRetryCount: 3,
|
||||||
services: ['phantomjs'],
|
|
||||||
framework: 'mocha',
|
framework: 'mocha',
|
||||||
reporters: ['spec'],
|
reporters: ['spec'],
|
||||||
phantomjsOpts: {
|
|
||||||
webdriverLogfile: 'phantomjs.log'
|
|
||||||
},
|
|
||||||
mochaOpts: {
|
mochaOpts: {
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
// Because we don't know how long the initial build will take...
|
// Because we don't know how long the initial build will take...
|
||||||
timeout: 4*60*1000
|
timeout: 4*60*1000
|
||||||
},
|
},
|
||||||
onPrepare: function (config, capabilities) {
|
onPrepare: function (config, capabilities) {
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
var compiler = webpack(webpackConfig);
|
var compiler = webpack(webpackConfig);
|
||||||
server = new WebpackDevServer(compiler, {});
|
server = new WebpackDevServer(compiler, {
|
||||||
server.listen(testConfig.port);
|
stats: {
|
||||||
|
colors: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.listen(testConfig.port, (isDocker() ? "0.0.0.0" : "localhost"), function(err) {
|
||||||
|
if(err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
},
|
},
|
||||||
onComplete: function(exitCode) {
|
onComplete: function(exitCode) {
|
||||||
server.close();
|
server.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
var webpack = require('webpack');
|
var webpack = require('webpack');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var loaders = require('./webpack.loaders');
|
var loaders = require('./webpack.loaders');
|
||||||
|
@ -7,15 +6,10 @@ var HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');
|
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');
|
||||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||||
var CopyWebpackPlugin = require('copy-webpack-plugin');
|
var CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||||
|
var artifacts = require("../test/artifacts");
|
||||||
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||||
|
|
||||||
var OUTPATH;
|
var OUTPATH = artifacts.pathSync("/build");
|
||||||
if(process.env.CIRCLE_ARTIFACTS) {
|
|
||||||
OUTPATH = path.join(process.env.CIRCLE_ARTIFACTS, "build");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OUTPATH = path.join(__dirname, '..', 'public');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: {
|
entry: {
|
||||||
|
|
7706
package-lock.json
generated
7706
package-lock.json
generated
File diff suppressed because it is too large
Load diff
28
package.json
28
package.json
|
@ -6,8 +6,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"stats": "webpack --config config/webpack.production.config.js --profile --json > stats.json",
|
"stats": "webpack --config config/webpack.production.config.js --profile --json > stats.json",
|
||||||
"build": "webpack --config config/webpack.production.config.js --progress --profile --colors",
|
"build": "webpack --config config/webpack.production.config.js --progress --profile --colors",
|
||||||
"test": "wdio config/wdio.conf.js",
|
"test": "cross-env NODE_ENV=test wdio config/wdio.conf.js",
|
||||||
"test-watch": "wdio config/wdio.conf.js --watch",
|
"test-watch": "cross-env NODE_ENV=test wdio config/wdio.conf.js --watch",
|
||||||
"start": "webpack-dev-server --progress --profile --colors --config config/webpack.config.js",
|
"start": "webpack-dev-server --progress --profile --colors --config config/webpack.config.js",
|
||||||
"lint": "eslint --ext js --ext jsx {src,test}",
|
"lint": "eslint --ext js --ext jsx {src,test}",
|
||||||
"lint-styles": "stylelint 'src/styles/*.scss'",
|
"lint-styles": "stylelint 'src/styles/*.scss'",
|
||||||
|
@ -40,14 +40,14 @@
|
||||||
"ol-mapbox-style": "^2.10.1",
|
"ol-mapbox-style": "^2.10.1",
|
||||||
"ol": "^4.6.4",
|
"ol": "^4.6.4",
|
||||||
"prop-types": "^15.6.0",
|
"prop-types": "^15.6.0",
|
||||||
"react": "16.0.0",
|
"react": "^16.2.0",
|
||||||
"react-addons-pure-render-mixin": "^15.6.2",
|
"react-addons-pure-render-mixin": "^15.6.2",
|
||||||
"react-autocomplete": "^1.7.2",
|
"react-autocomplete": "^1.7.2",
|
||||||
"react-codemirror2": "^3.0.7",
|
"react-codemirror2": "^3.0.7",
|
||||||
"react-collapse": "^4.0.3",
|
"react-collapse": "^4.0.3",
|
||||||
"react-color": "^2.13.8",
|
"react-color": "^2.13.8",
|
||||||
"react-copy-to-clipboard": "^5.0.1",
|
"react-copy-to-clipboard": "^5.0.1",
|
||||||
"react-dom": "16.0.0",
|
"react-dom": "^16.2.0",
|
||||||
"react-file-reader-input": "^1.1.4",
|
"react-file-reader-input": "^1.1.4",
|
||||||
"react-height": "^3.0.0",
|
"react-height": "^3.0.0",
|
||||||
"react-icon-base": "^2.1.1",
|
"react-icon-base": "^2.1.1",
|
||||||
|
@ -91,6 +91,7 @@
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-eslint": "^8.0.2",
|
"babel-eslint": "^8.0.2",
|
||||||
"babel-loader": "7.1.1",
|
"babel-loader": "7.1.1",
|
||||||
|
"babel-plugin-istanbul": "^4.1.5",
|
||||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||||
"babel-plugin-transform-flow-strip-types": "^6.22.0",
|
"babel-plugin-transform-flow-strip-types": "^6.22.0",
|
||||||
|
@ -100,36 +101,41 @@
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-flow": "^6.23.0",
|
"babel-preset-flow": "^6.23.0",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
|
"babel-register": "^6.26.0",
|
||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"base64-loader": "^1.0.0",
|
"base64-loader": "^1.0.0",
|
||||||
"copy-webpack-plugin": "^4.2.0",
|
"copy-webpack-plugin": "^4.2.0",
|
||||||
|
"cors": "^2.8.4",
|
||||||
|
"cross-env": "^5.1.3",
|
||||||
"css-loader": "^0.28.7",
|
"css-loader": "^0.28.7",
|
||||||
"eslint": "^4.10.0",
|
"eslint": "^4.10.0",
|
||||||
"eslint-plugin-react": "^7.4.0",
|
"eslint-plugin-react": "^7.4.0",
|
||||||
|
"express": "^4.16.2",
|
||||||
"extract-text-webpack-plugin": "^3.0.2",
|
"extract-text-webpack-plugin": "^3.0.2",
|
||||||
"file-loader": "^1.1.5",
|
"file-loader": "^1.1.5",
|
||||||
"html-webpack-plugin": "^2.30.1",
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"is-docker": "^1.1.0",
|
||||||
|
"istanbul": "^0.4.5",
|
||||||
|
"istanbul-lib-coverage": "^1.1.1",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"karma": "^1.7.1",
|
"mkdirp": "^0.5.1",
|
||||||
"karma-chrome-launcher": "^2.2.0",
|
|
||||||
"karma-firefox-launcher": "^1.0.1",
|
|
||||||
"karma-mocha": "^1.3.0",
|
|
||||||
"karma-webpack": "^2.0.5",
|
|
||||||
"mocha": "^4.0.1",
|
"mocha": "^4.0.1",
|
||||||
"mocha-loader": "^1.1.1",
|
|
||||||
"node-sass": "^4.6.0",
|
"node-sass": "^4.6.0",
|
||||||
"nsp": "^3.1.0",
|
"nsp": "^3.1.0",
|
||||||
"react-hot-loader": "^3.1.1",
|
"react-hot-loader": "^3.1.1",
|
||||||
"sass-loader": "^6.0.6",
|
"sass-loader": "^6.0.6",
|
||||||
|
"selenium-standalone": "^6.13.0",
|
||||||
"style-loader": "^0.19.0",
|
"style-loader": "^0.19.0",
|
||||||
"stylelint": "^7.13.0",
|
"stylelint": "^7.13.0",
|
||||||
"stylelint-config-standard": "^15.0.1",
|
"stylelint-config-standard": "^15.0.1",
|
||||||
"transform-loader": "^0.2.4",
|
"transform-loader": "^0.2.4",
|
||||||
|
"uuid": "^3.1.0",
|
||||||
"uglifyjs-webpack-plugin": "^1.1.8",
|
"uglifyjs-webpack-plugin": "^1.1.8",
|
||||||
"wdio-mocha-framework": "^0.5.11",
|
"wdio-mocha-framework": "^0.5.11",
|
||||||
"wdio-phantomjs-service": "^0.2.2",
|
"wdio-phantomjs-service": "^0.2.2",
|
||||||
|
"wdio-selenium-standalone-service": "0.0.9",
|
||||||
"wdio-spec-reporter": "^0.1.2",
|
"wdio-spec-reporter": "^0.1.2",
|
||||||
"webdriverio": "^4.8.0",
|
"webdriverio": "^4.12.0",
|
||||||
"webpack": "^3.8.1",
|
"webpack": "^3.8.1",
|
||||||
"webpack-bundle-analyzer": "^2.9.0",
|
"webpack-bundle-analyzer": "^2.9.0",
|
||||||
"webpack-cleanup-plugin": "^0.5.1",
|
"webpack-cleanup-plugin": "^0.5.1",
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { RevisionStore } from '../libs/revisions'
|
||||||
import LayerWatcher from '../libs/layerwatcher'
|
import LayerWatcher from '../libs/layerwatcher'
|
||||||
import tokens from '../config/tokens.json'
|
import tokens from '../config/tokens.json'
|
||||||
import isEqual from 'lodash.isequal'
|
import isEqual from 'lodash.isequal'
|
||||||
|
import Debug from '../libs/debug'
|
||||||
|
|
||||||
import MapboxGl from 'mapbox-gl'
|
import MapboxGl from 'mapbox-gl'
|
||||||
import mapboxUtil from 'mapbox-gl/src/util/mapbox'
|
import mapboxUtil from 'mapbox-gl/src/util/mapbox'
|
||||||
|
@ -57,9 +58,19 @@ export default class App extends React.Component {
|
||||||
this.styleStore = new StyleStore()
|
this.styleStore = new StyleStore()
|
||||||
}
|
}
|
||||||
this.styleStore.latestStyle(mapStyle => this.onStyleChanged(mapStyle))
|
this.styleStore.latestStyle(mapStyle => this.onStyleChanged(mapStyle))
|
||||||
|
|
||||||
|
if(Debug.enabled()) {
|
||||||
|
Debug.set("maputnik", "styleStore", this.styleStore);
|
||||||
|
Debug.set("maputnik", "revisionStore", this.revisionStore);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Debug.enabled()) {
|
||||||
|
Debug.set("maputnik", "revisionStore", this.revisionStore);
|
||||||
|
Debug.set("maputnik", "styleStore", this.styleStore);
|
||||||
|
}
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
errors: [],
|
errors: [],
|
||||||
infos: [],
|
infos: [],
|
||||||
|
@ -86,11 +97,6 @@ export default class App extends React.Component {
|
||||||
Mousetrap.unbind(['mod+y', 'mod+shift+z'], this.onRedo.bind(this));
|
Mousetrap.unbind(['mod+y', 'mod+shift+z'], this.onRedo.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
onReset() {
|
|
||||||
this.styleStore.purge()
|
|
||||||
loadDefaultStyle(mapStyle => this.onStyleOpen(mapStyle))
|
|
||||||
}
|
|
||||||
|
|
||||||
saveStyle(snapshotStyle) {
|
saveStyle(snapshotStyle) {
|
||||||
this.styleStore.save(snapshotStyle)
|
this.styleStore.save(snapshotStyle)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import classnames from 'classnames'
|
||||||
|
|
||||||
class Button extends React.Component {
|
class Button extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
"data-wd-key": PropTypes.string,
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
|
@ -14,6 +15,7 @@ class Button extends React.Component {
|
||||||
return <a
|
return <a
|
||||||
onClick={this.props.onClick}
|
onClick={this.props.onClick}
|
||||||
className={classnames("maputnik-button", this.props.className)}
|
className={classnames("maputnik-button", this.props.className)}
|
||||||
|
data-wd-key={this.props["data-wd-key"]}
|
||||||
style={this.props.style}>
|
style={this.props.style}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -58,12 +58,14 @@ class ToolbarLink extends React.Component {
|
||||||
class ToolbarAction extends React.Component {
|
class ToolbarAction extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
onClick: PropTypes.func
|
onClick: PropTypes.func,
|
||||||
|
wdKey: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <a
|
return <a
|
||||||
className='maputnik-toolbar-action'
|
className='maputnik-toolbar-action'
|
||||||
|
data-wd-key={this.props.wdKey}
|
||||||
onClick={this.props.onClick}
|
onClick={this.props.onClick}
|
||||||
>
|
>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
|
@ -142,23 +144,23 @@ export default class Toolbar extends React.Component {
|
||||||
</h1>
|
</h1>
|
||||||
</ToolbarLink>
|
</ToolbarLink>
|
||||||
<div className="maputnik-toolbar__actions">
|
<div className="maputnik-toolbar__actions">
|
||||||
<ToolbarAction onClick={this.toggleModal.bind(this, 'open')}>
|
<ToolbarAction wdKey="nav:open" onClick={this.toggleModal.bind(this, 'open')}>
|
||||||
<OpenIcon />
|
<OpenIcon />
|
||||||
<IconText>Open</IconText>
|
<IconText>Open</IconText>
|
||||||
</ToolbarAction>
|
</ToolbarAction>
|
||||||
<ToolbarAction onClick={this.toggleModal.bind(this, 'export')}>
|
<ToolbarAction wdKey="nav:export" onClick={this.toggleModal.bind(this, 'export')}>
|
||||||
<MdFileDownload />
|
<MdFileDownload />
|
||||||
<IconText>Export</IconText>
|
<IconText>Export</IconText>
|
||||||
</ToolbarAction>
|
</ToolbarAction>
|
||||||
<ToolbarAction onClick={this.toggleModal.bind(this, 'sources')}>
|
<ToolbarAction wdKey="nav:sources" onClick={this.toggleModal.bind(this, 'sources')}>
|
||||||
<SourcesIcon />
|
<SourcesIcon />
|
||||||
<IconText>Sources</IconText>
|
<IconText>Sources</IconText>
|
||||||
</ToolbarAction>
|
</ToolbarAction>
|
||||||
<ToolbarAction onClick={this.toggleModal.bind(this, 'settings')}>
|
<ToolbarAction wdKey="nav:settings" onClick={this.toggleModal.bind(this, 'settings')}>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
<IconText>Style Settings</IconText>
|
<IconText>Style Settings</IconText>
|
||||||
</ToolbarAction>
|
</ToolbarAction>
|
||||||
<ToolbarAction onClick={this.props.onInspectModeToggle}>
|
<ToolbarAction wdKey="nav:inspect" onClick={this.props.onInspectModeToggle}>
|
||||||
<InspectionIcon />
|
<InspectionIcon />
|
||||||
<IconText>
|
<IconText>
|
||||||
{ this.props.inspectModeEnabled && <span>Map Mode</span> }
|
{ this.props.inspectModeEnabled && <span>Map Mode</span> }
|
||||||
|
|
|
@ -131,8 +131,7 @@ export default class FunctionSpecProperty extends React.Component {
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
return <div className={propClass} data-wd-key={"spec-field:"+this.props.fieldName}>
|
||||||
return <div className={propClass}>
|
|
||||||
{specField}
|
{specField}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,8 @@ export default class SpecField extends React.Component {
|
||||||
name: this.props.fieldName,
|
name: this.props.fieldName,
|
||||||
onChange: newValue => this.props.onChange(this.props.fieldName, newValue)
|
onChange: newValue => this.props.onChange(this.props.fieldName, newValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function childNodes() {
|
||||||
switch(this.props.fieldSpec.type) {
|
switch(this.props.fieldSpec.type) {
|
||||||
case 'number': return (
|
case 'number': return (
|
||||||
<NumberInput
|
<NumberInput
|
||||||
|
@ -124,4 +126,11 @@ export default class SpecField extends React.Component {
|
||||||
default: return null
|
default: return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div data-wd-key={"spec-field:"+this.props.fieldName}>
|
||||||
|
{childNodes.call(this)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default class CombiningFilterEditor extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="maputnik-filter-editor">
|
return <div className="maputnik-filter-editor">
|
||||||
<div className="maputnik-filter-editor-compound-select">
|
<div className="maputnik-filter-editor-compound-select" data-wd-key="layer-filter">
|
||||||
<DocLabel
|
<DocLabel
|
||||||
label={"Compound Filter"}
|
label={"Compound Filter"}
|
||||||
doc={styleSpec.latest.layer.filter.doc + " Combine multiple filters together by using a compound filter."}
|
doc={styleSpec.latest.layer.filter.doc + " Combine multiple filters together by using a compound filter."}
|
||||||
|
@ -103,6 +103,7 @@ export default class CombiningFilterEditor extends React.Component {
|
||||||
{editorBlocks}
|
{editorBlocks}
|
||||||
<div className="maputnik-filter-editor-add-wrapper">
|
<div className="maputnik-filter-editor-add-wrapper">
|
||||||
<Button
|
<Button
|
||||||
|
data-wd-key="layer-filter-button"
|
||||||
className="maputnik-add-filter"
|
className="maputnik-add-filter"
|
||||||
onClick={this.addFilterItem.bind(this)}>
|
onClick={this.addFilterItem.bind(this)}>
|
||||||
Add filter
|
Add filter
|
||||||
|
|
|
@ -25,7 +25,6 @@ class LayerIcon extends React.Component {
|
||||||
case 'line': return <LineIcon {...iconProps} />
|
case 'line': return <LineIcon {...iconProps} />
|
||||||
case 'symbol': return <SymbolIcon {...iconProps} />
|
case 'symbol': return <SymbolIcon {...iconProps} />
|
||||||
case 'circle': return <CircleIcon {...iconProps} />
|
case 'circle': return <CircleIcon {...iconProps} />
|
||||||
default: return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import DocLabel from '../fields/DocLabel'
|
||||||
/** Wrap a component with a label */
|
/** Wrap a component with a label */
|
||||||
class InputBlock extends React.Component {
|
class InputBlock extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
"data-wd-key": PropTypes.string,
|
||||||
label: PropTypes.oneOfType([
|
label: PropTypes.oneOfType([
|
||||||
PropTypes.string,
|
PropTypes.string,
|
||||||
PropTypes.element,
|
PropTypes.element,
|
||||||
|
@ -24,6 +25,7 @@ class InputBlock extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div style={this.props.style}
|
return <div style={this.props.style}
|
||||||
|
data-wd-key={this.props["data-wd-key"]}
|
||||||
className={classnames({
|
className={classnames({
|
||||||
"maputnik-input-block": true,
|
"maputnik-input-block": true,
|
||||||
"maputnik-action-block": this.props.action
|
"maputnik-action-block": this.props.action
|
||||||
|
|
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types'
|
||||||
class SelectInput extends React.Component {
|
class SelectInput extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
|
"data-wd-key": PropTypes.string.isRequired,
|
||||||
options: PropTypes.array.isRequired,
|
options: PropTypes.array.isRequired,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
|
@ -18,6 +19,7 @@ class SelectInput extends React.Component {
|
||||||
|
|
||||||
return <select
|
return <select
|
||||||
className="maputnik-select"
|
className="maputnik-select"
|
||||||
|
data-wd-key={this.props["data-wd-key"]}
|
||||||
style={this.props.style}
|
style={this.props.style}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
onChange={e => this.props.onChange(e.target.value)}
|
onChange={e => this.props.onChange(e.target.value)}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types'
|
||||||
|
|
||||||
class StringInput extends React.Component {
|
class StringInput extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
"data-wd-key": PropTypes.string,
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
default: PropTypes.string,
|
default: PropTypes.string,
|
||||||
|
@ -40,11 +41,16 @@ class StringInput extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return React.createElement(tag, {
|
return React.createElement(tag, {
|
||||||
|
"data-wd-key": this.props["data-wd-key"],
|
||||||
className: classes.join(" "),
|
className: classes.join(" "),
|
||||||
style: this.props.style,
|
style: this.props.style,
|
||||||
value: this.state.value,
|
value: this.state.value,
|
||||||
placeholder: this.props.default,
|
placeholder: this.props.default,
|
||||||
onChange: e => this.setState({ value: e.target.value }),
|
onChange: e => {
|
||||||
|
this.setState({
|
||||||
|
value: e.target.value
|
||||||
|
})
|
||||||
|
},
|
||||||
onBlur: () => {
|
onBlur: () => {
|
||||||
if(this.state.value!==this.props.value) this.props.onChange(this.state.value)
|
if(this.state.value!==this.props.value) this.props.onChange(this.state.value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,11 @@ class MetadataBlock extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"Comments"} doc={"Comments for the current layer. This is non-standard and not in the spec."}>
|
return <InputBlock
|
||||||
|
label={"Comments"}
|
||||||
|
doc={"Comments for the current layer. This is non-standard and not in the spec."}
|
||||||
|
data-wd-key="layer-comment"
|
||||||
|
>
|
||||||
<StringInput
|
<StringInput
|
||||||
multi={true}
|
multi={true}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import PropTypes from 'prop-types'
|
||||||
import {Controlled as CodeMirror} from 'react-codemirror2'
|
import {Controlled as CodeMirror} from 'react-codemirror2'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
|
||||||
|
|
||||||
import 'codemirror/mode/javascript/javascript'
|
import 'codemirror/mode/javascript/javascript'
|
||||||
import 'codemirror/addon/lint/lint'
|
import 'codemirror/addon/lint/lint'
|
||||||
|
|
|
@ -19,11 +19,6 @@ import MultiButtonInput from '../inputs/MultiButtonInput'
|
||||||
import { changeType, changeProperty } from '../../libs/layer'
|
import { changeType, changeProperty } from '../../libs/layer'
|
||||||
import layout from '../../config/layout.json'
|
import layout from '../../config/layout.json'
|
||||||
|
|
||||||
class UnsupportedLayer extends React.Component {
|
|
||||||
render() {
|
|
||||||
return <div></div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function layoutGroups(layerType) {
|
function layoutGroups(layerType) {
|
||||||
const layerGroup = {
|
const layerGroup = {
|
||||||
|
@ -126,6 +121,7 @@ export default class LayerEditor extends React.Component {
|
||||||
case 'layer': return <div>
|
case 'layer': return <div>
|
||||||
<LayerIdBlock
|
<LayerIdBlock
|
||||||
value={this.props.layer.id}
|
value={this.props.layer.id}
|
||||||
|
wdKey="layer-editor.layer-id"
|
||||||
onChange={newId => this.props.onLayerIdChange(this.props.layer.id, newId)}
|
onChange={newId => this.props.onLayerIdChange(this.props.layer.id, newId)}
|
||||||
/>
|
/>
|
||||||
<LayerTypeBlock
|
<LayerTypeBlock
|
||||||
|
@ -177,7 +173,6 @@ export default class LayerEditor extends React.Component {
|
||||||
layer={this.props.layer}
|
layer={this.props.layer}
|
||||||
onChange={this.props.onLayerChanged}
|
onChange={this.props.onLayerChanged}
|
||||||
/>
|
/>
|
||||||
default: return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +182,7 @@ export default class LayerEditor extends React.Component {
|
||||||
return !(layerType === 'background' && group.type === 'source')
|
return !(layerType === 'background' && group.type === 'source')
|
||||||
}).map(group => {
|
}).map(group => {
|
||||||
return <LayerEditorGroup
|
return <LayerEditorGroup
|
||||||
|
data-wd-key={group.title}
|
||||||
key={group.title}
|
key={group.title}
|
||||||
title={group.title}
|
title={group.title}
|
||||||
isActive={this.state.editorGroups[group.title]}
|
isActive={this.state.editorGroups[group.title]}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Collapser from './Collapser'
|
||||||
|
|
||||||
export default class LayerEditorGroup extends React.Component {
|
export default class LayerEditorGroup extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
"data-wd-key": PropTypes.string,
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
isActive: PropTypes.bool.isRequired,
|
isActive: PropTypes.bool.isRequired,
|
||||||
children: PropTypes.element.isRequired,
|
children: PropTypes.element.isRequired,
|
||||||
|
@ -14,6 +15,7 @@ export default class LayerEditorGroup extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return <div>
|
return <div>
|
||||||
<div className="maputnik-layer-editor-group"
|
<div className="maputnik-layer-editor-group"
|
||||||
|
data-wd-key={"layer-editor-group:"+this.props["data-wd-key"]}
|
||||||
onClick={e => this.props.onActiveToggle(!this.props.isActive)}
|
onClick={e => this.props.onActiveToggle(!this.props.isActive)}
|
||||||
>
|
>
|
||||||
<span>{this.props.title}</span>
|
<span>{this.props.title}</span>
|
||||||
|
|
|
@ -8,11 +8,14 @@ import StringInput from '../inputs/StringInput'
|
||||||
class LayerIdBlock extends React.Component {
|
class LayerIdBlock extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
|
wdKey: PropTypes.string.isRequired,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"ID"} doc={styleSpec.latest.layer.id.doc}>
|
return <InputBlock label={"ID"} doc={styleSpec.latest.layer.id.doc}
|
||||||
|
data-wd-key={this.props.wdKey}
|
||||||
|
>
|
||||||
<StringInput
|
<StringInput
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
|
|
|
@ -162,6 +162,7 @@ class LayerListContainer extends React.Component {
|
||||||
const groupPrefix = layerPrefix(layers[0].id)
|
const groupPrefix = layerPrefix(layers[0].id)
|
||||||
if(layers.length > 1) {
|
if(layers.length > 1) {
|
||||||
const grp = <LayerListGroup
|
const grp = <LayerListGroup
|
||||||
|
data-wd-key={[groupPrefix, idx].join('-')}
|
||||||
key={[groupPrefix, idx].join('-')}
|
key={[groupPrefix, idx].join('-')}
|
||||||
title={groupPrefix}
|
title={groupPrefix}
|
||||||
isActive={!this.isCollapsed(groupPrefix, idx) || idx === this.props.selectedLayerIndex}
|
isActive={!this.isCollapsed(groupPrefix, idx) || idx === this.props.selectedLayerIndex}
|
||||||
|
@ -218,6 +219,7 @@ class LayerListContainer extends React.Component {
|
||||||
<div className="maputnik-multibutton">
|
<div className="maputnik-multibutton">
|
||||||
<a
|
<a
|
||||||
onClick={this.toggleModal.bind(this, 'add')}
|
onClick={this.toggleModal.bind(this, 'add')}
|
||||||
|
data-wd-key="layer-list:add-layer"
|
||||||
className="maputnik-button maputnik-button-selected">
|
className="maputnik-button maputnik-button-selected">
|
||||||
Add Layer
|
Add Layer
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Collapser from './Collapser'
|
||||||
export default class LayerListGroup extends React.Component {
|
export default class LayerListGroup extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
|
"data-wd-key": PropTypes.string,
|
||||||
isActive: PropTypes.bool.isRequired,
|
isActive: PropTypes.bool.isRequired,
|
||||||
onActiveToggle: PropTypes.func.isRequired
|
onActiveToggle: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
@ -12,6 +13,7 @@ export default class LayerListGroup extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return <li className="maputnik-layer-list-group">
|
return <li className="maputnik-layer-list-group">
|
||||||
<div className="maputnik-layer-list-group-header"
|
<div className="maputnik-layer-list-group-header"
|
||||||
|
data-wd-key={"layer-list-group:"+this.props["data-wd-key"]}
|
||||||
onClick={e => this.props.onActiveToggle(!this.props.isActive)}
|
onClick={e => this.props.onActiveToggle(!this.props.isActive)}
|
||||||
>
|
>
|
||||||
<span className="maputnik-layer-list-group-title">{this.props.title}</span>
|
<span className="maputnik-layer-list-group-title">{this.props.title}</span>
|
||||||
|
|
|
@ -33,6 +33,7 @@ class IconAction extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
action: PropTypes.string.isRequired,
|
action: PropTypes.string.isRequired,
|
||||||
onClick: PropTypes.func.isRequired,
|
onClick: PropTypes.func.isRequired,
|
||||||
|
wdKey: PropTypes.string
|
||||||
}
|
}
|
||||||
|
|
||||||
renderIcon() {
|
renderIcon() {
|
||||||
|
@ -41,13 +42,13 @@ class IconAction extends React.Component {
|
||||||
case 'show': return <VisibilityIcon />
|
case 'show': return <VisibilityIcon />
|
||||||
case 'hide': return <VisibilityOffIcon />
|
case 'hide': return <VisibilityOffIcon />
|
||||||
case 'delete': return <DeleteIcon />
|
case 'delete': return <DeleteIcon />
|
||||||
default: return null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <a
|
return <a
|
||||||
className="maputnik-layer-list-icon-action"
|
className="maputnik-layer-list-icon-action"
|
||||||
|
data-wd-key={this.props.wdKey}
|
||||||
onClick={this.props.onClick}
|
onClick={this.props.onClick}
|
||||||
>
|
>
|
||||||
{this.renderIcon()}
|
{this.renderIcon()}
|
||||||
|
@ -92,6 +93,7 @@ class LayerListItem extends React.Component {
|
||||||
return <li
|
return <li
|
||||||
key={this.props.layerId}
|
key={this.props.layerId}
|
||||||
onClick={e => this.props.onLayerSelect(this.props.layerId)}
|
onClick={e => this.props.onLayerSelect(this.props.layerId)}
|
||||||
|
data-wd-key={"layer-list-item:"+this.props.layerId}
|
||||||
className={classnames({
|
className={classnames({
|
||||||
"maputnik-layer-list-item": true,
|
"maputnik-layer-list-item": true,
|
||||||
"maputnik-layer-list-item-selected": this.props.isSelected,
|
"maputnik-layer-list-item-selected": this.props.isSelected,
|
||||||
|
@ -101,14 +103,17 @@ class LayerListItem extends React.Component {
|
||||||
<span className="maputnik-layer-list-item-id">{this.props.layerId}</span>
|
<span className="maputnik-layer-list-item-id">{this.props.layerId}</span>
|
||||||
<span style={{flexGrow: 1}} />
|
<span style={{flexGrow: 1}} />
|
||||||
<IconAction
|
<IconAction
|
||||||
|
wdKey={"layer-list-item:"+this.props.layerId+":delete"}
|
||||||
action={'delete'}
|
action={'delete'}
|
||||||
onClick={e => this.props.onLayerDestroy(this.props.layerId)}
|
onClick={e => this.props.onLayerDestroy(this.props.layerId)}
|
||||||
/>
|
/>
|
||||||
<IconAction
|
<IconAction
|
||||||
|
wdKey={"layer-list-item:"+this.props.layerId+":copy"}
|
||||||
action={'copy'}
|
action={'copy'}
|
||||||
onClick={e => this.props.onLayerCopy(this.props.layerId)}
|
onClick={e => this.props.onLayerCopy(this.props.layerId)}
|
||||||
/>
|
/>
|
||||||
<IconAction
|
<IconAction
|
||||||
|
wdKey={"layer-list-item:"+this.props.layerId+":toggle-visibility"}
|
||||||
action={this.props.visibility === 'visible' ? 'hide' : 'show'}
|
action={this.props.visibility === 'visible' ? 'hide' : 'show'}
|
||||||
onClick={e => this.props.onLayerVisibilityToggle(this.props.layerId)}
|
onClick={e => this.props.onLayerVisibilityToggle(this.props.layerId)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -4,12 +4,12 @@ import PropTypes from 'prop-types'
|
||||||
import styleSpec from '@mapbox/mapbox-gl-style-spec/style-spec'
|
import styleSpec from '@mapbox/mapbox-gl-style-spec/style-spec'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
|
||||||
import AutocompleteInput from '../inputs/AutocompleteInput'
|
import AutocompleteInput from '../inputs/AutocompleteInput'
|
||||||
|
|
||||||
class LayerSourceBlock extends React.Component {
|
class LayerSourceBlock extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
value: PropTypes.string,
|
value: PropTypes.string,
|
||||||
|
wdKey: PropTypes.string,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
sourceIds: PropTypes.array,
|
sourceIds: PropTypes.array,
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ class LayerSourceBlock extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"Source"} doc={styleSpec.latest.layer.source.doc}>
|
return <InputBlock label={"Source"} doc={styleSpec.latest.layer.source.doc}
|
||||||
|
data-wd-key={this.props.wdKey}
|
||||||
|
>
|
||||||
<AutocompleteInput
|
<AutocompleteInput
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import PropTypes from 'prop-types'
|
||||||
import styleSpec from '@mapbox/mapbox-gl-style-spec/style-spec'
|
import styleSpec from '@mapbox/mapbox-gl-style-spec/style-spec'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
|
||||||
import AutocompleteInput from '../inputs/AutocompleteInput'
|
import AutocompleteInput from '../inputs/AutocompleteInput'
|
||||||
|
|
||||||
class LayerSourceLayer extends React.Component {
|
class LayerSourceLayer extends React.Component {
|
||||||
|
@ -22,7 +21,9 @@ class LayerSourceLayer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"Source Layer"} doc={styleSpec.latest.layer['source-layer'].doc}>
|
return <InputBlock label={"Source Layer"} doc={styleSpec.latest.layer['source-layer'].doc}
|
||||||
|
data-wd-key="layer-source-layer"
|
||||||
|
>
|
||||||
<AutocompleteInput
|
<AutocompleteInput
|
||||||
keepMenuWithinWindowBounds={!!this.props.isFixed}
|
keepMenuWithinWindowBounds={!!this.props.isFixed}
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
|
|
|
@ -8,11 +8,14 @@ import SelectInput from '../inputs/SelectInput'
|
||||||
class LayerTypeBlock extends React.Component {
|
class LayerTypeBlock extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
|
wdKey: PropTypes.string.isRequired,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"Type"} doc={styleSpec.latest.layer.type.doc}>
|
return <InputBlock label={"Type"} doc={styleSpec.latest.layer.type.doc}
|
||||||
|
data-wd-key={this.props.wdKey}
|
||||||
|
>
|
||||||
<SelectInput
|
<SelectInput
|
||||||
options={[
|
options={[
|
||||||
['background', 'Background'],
|
['background', 'Background'],
|
||||||
|
|
|
@ -12,7 +12,9 @@ class MaxZoomBlock extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"Max Zoom"} doc={styleSpec.latest.layer.maxzoom.doc}>
|
return <InputBlock label={"Max Zoom"} doc={styleSpec.latest.layer.maxzoom.doc}
|
||||||
|
data-wd-key="max-zoom"
|
||||||
|
>
|
||||||
<NumberInput
|
<NumberInput
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
|
|
|
@ -12,7 +12,9 @@ class MinZoomBlock extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <InputBlock label={"Min Zoom"} doc={styleSpec.latest.layer.minzoom.doc}>
|
return <InputBlock label={"Min Zoom"} doc={styleSpec.latest.layer.minzoom.doc}
|
||||||
|
data-wd-key="min-zoom"
|
||||||
|
>
|
||||||
<NumberInput
|
<NumberInput
|
||||||
value={this.props.value}
|
value={this.props.value}
|
||||||
onChange={this.props.onChange}
|
onChange={this.props.onChange}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import PropTypes from 'prop-types'
|
||||||
import Button from '../Button'
|
import Button from '../Button'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
|
|
||||||
import LayerTypeBlock from '../layers/LayerTypeBlock'
|
import LayerTypeBlock from '../layers/LayerTypeBlock'
|
||||||
|
@ -119,19 +118,25 @@ class AddModal extends React.Component {
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Add Layer'}
|
title={'Add Layer'}
|
||||||
|
data-wd-key="modal:add-layer"
|
||||||
>
|
>
|
||||||
<div className="maputnik-add-layer">
|
<div className="maputnik-add-layer">
|
||||||
<LayerIdBlock
|
<LayerIdBlock
|
||||||
value={this.state.id}
|
value={this.state.id}
|
||||||
onChange={v => this.setState({ id: v })}
|
wdKey="add-layer.layer-id"
|
||||||
|
onChange={v => {
|
||||||
|
this.setState({ id: v })
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<LayerTypeBlock
|
<LayerTypeBlock
|
||||||
value={this.state.type}
|
value={this.state.type}
|
||||||
|
wdKey="add-layer.layer-type"
|
||||||
onChange={v => this.setState({ type: v })}
|
onChange={v => this.setState({ type: v })}
|
||||||
/>
|
/>
|
||||||
{this.state.type !== 'background' &&
|
{this.state.type !== 'background' &&
|
||||||
<LayerSourceBlock
|
<LayerSourceBlock
|
||||||
sourceIds={sources}
|
sourceIds={sources}
|
||||||
|
wdKey="add-layer.layer-source-block"
|
||||||
value={this.state.source}
|
value={this.state.source}
|
||||||
onChange={v => this.setState({ source: v })}
|
onChange={v => this.setState({ source: v })}
|
||||||
/>
|
/>
|
||||||
|
@ -144,7 +149,11 @@ class AddModal extends React.Component {
|
||||||
onChange={v => this.setState({ 'source-layer': v })}
|
onChange={v => this.setState({ 'source-layer': v })}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<Button className="maputnik-add-layer-button" onClick={this.addLayer.bind(this)}>
|
<Button
|
||||||
|
className="maputnik-add-layer-button"
|
||||||
|
onClick={this.addLayer.bind(this)}
|
||||||
|
data-wd-key="add-layer"
|
||||||
|
>
|
||||||
Add Layer
|
Add Layer
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { saveAs } from 'file-saver'
|
||||||
import styleSpec from '@mapbox/mapbox-gl-style-spec/style-spec'
|
import styleSpec from '@mapbox/mapbox-gl-style-spec/style-spec'
|
||||||
import InputBlock from '../inputs/InputBlock'
|
import InputBlock from '../inputs/InputBlock'
|
||||||
import StringInput from '../inputs/StringInput'
|
import StringInput from '../inputs/StringInput'
|
||||||
import SelectInput from '../inputs/SelectInput'
|
|
||||||
import CheckboxInput from '../inputs/CheckboxInput'
|
import CheckboxInput from '../inputs/CheckboxInput'
|
||||||
import Button from '../Button'
|
import Button from '../Button'
|
||||||
import Modal from './Modal'
|
import Modal from './Modal'
|
||||||
|
@ -242,6 +241,7 @@ class ExportModal extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Modal
|
return <Modal
|
||||||
|
data-wd-key="export-modal"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Export Style'}
|
title={'Export Style'}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Overlay from './Overlay'
|
||||||
|
|
||||||
class Modal extends React.Component {
|
class Modal extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
"data-wd-key": PropTypes.string,
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
title: PropTypes.string.isRequired,
|
title: PropTypes.string.isRequired,
|
||||||
onOpenToggle: PropTypes.func.isRequired,
|
onOpenToggle: PropTypes.func.isRequired,
|
||||||
|
@ -13,12 +14,15 @@ class Modal extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <Overlay isOpen={this.props.isOpen}>
|
return <Overlay isOpen={this.props.isOpen}>
|
||||||
<div className="maputnik-modal">
|
<div className="maputnik-modal"
|
||||||
|
data-wd-key={this.props["data-wd-key"]}
|
||||||
|
>
|
||||||
<header className="maputnik-modal-header">
|
<header className="maputnik-modal-header">
|
||||||
<h1 className="maputnik-modal-header-title">{this.props.title}</h1>
|
<h1 className="maputnik-modal-header-title">{this.props.title}</h1>
|
||||||
<span className="maputnik-modal-header-space"></span>
|
<span className="maputnik-modal-header-space"></span>
|
||||||
<a className="maputnik-modal-header-toggle"
|
<a className="maputnik-modal-header-toggle"
|
||||||
onClick={() => this.props.onOpenToggle(false)}
|
onClick={() => this.props.onOpenToggle(false)}
|
||||||
|
data-wd-key={this.props["data-wd-key"]+".close-modal"}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -133,6 +133,7 @@ class OpenModal extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Modal
|
return <Modal
|
||||||
|
data-wd-key="open-modal"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={() => this.onOpenToggle()}
|
onOpenToggle={() => this.onOpenToggle()}
|
||||||
title={'Open Style'}
|
title={'Open Style'}
|
||||||
|
@ -151,9 +152,9 @@ class OpenModal extends React.Component {
|
||||||
<p>
|
<p>
|
||||||
Load from a URL. Note that the URL must have <a href="https://enable-cors.org" target="_blank" rel="noopener noreferrer">CORS enabled</a>.
|
Load from a URL. Note that the URL must have <a href="https://enable-cors.org" target="_blank" rel="noopener noreferrer">CORS enabled</a>.
|
||||||
</p>
|
</p>
|
||||||
<input type="text" ref={(input) => this.styleUrlElement = input} className="maputnik-input" placeholder="Enter URL..."/>
|
<input data-wd-key="open-modal.url.input" type="text" ref={(input) => this.styleUrlElement = input} className="maputnik-input" placeholder="Enter URL..."/>
|
||||||
<div>
|
<div>
|
||||||
<Button className="maputnik-big-button" onClick={this.onOpenUrl.bind(this)}>Open URL</Button>
|
<Button data-wd-key="open-modal.url.button" className="maputnik-big-button" onClick={this.onOpenUrl.bind(this)}>Open URL</Button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ class SettingsModal extends React.Component {
|
||||||
const metadata = this.props.mapStyle.metadata || {}
|
const metadata = this.props.mapStyle.metadata || {}
|
||||||
const inputProps = { }
|
const inputProps = { }
|
||||||
return <Modal
|
return <Modal
|
||||||
|
data-wd-key="modal-settings"
|
||||||
isOpen={this.props.isOpen}
|
isOpen={this.props.isOpen}
|
||||||
onOpenToggle={this.props.onOpenToggle}
|
onOpenToggle={this.props.onOpenToggle}
|
||||||
title={'Style Settings'}
|
title={'Style Settings'}
|
||||||
|
@ -49,18 +50,21 @@ class SettingsModal extends React.Component {
|
||||||
<div style={{minWidth: 350}}>
|
<div style={{minWidth: 350}}>
|
||||||
<InputBlock label={"Name"} doc={styleSpec.latest.$root.name.doc}>
|
<InputBlock label={"Name"} doc={styleSpec.latest.$root.name.doc}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.name"
|
||||||
value={this.props.mapStyle.name}
|
value={this.props.mapStyle.name}
|
||||||
onChange={this.changeStyleProperty.bind(this, "name")}
|
onChange={this.changeStyleProperty.bind(this, "name")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Owner"} doc={"Owner ID of the style. Used by Mapbox or future style APIs."}>
|
<InputBlock label={"Owner"} doc={"Owner ID of the style. Used by Mapbox or future style APIs."}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.owner"
|
||||||
value={this.props.mapStyle.owner}
|
value={this.props.mapStyle.owner}
|
||||||
onChange={this.changeStyleProperty.bind(this, "owner")}
|
onChange={this.changeStyleProperty.bind(this, "owner")}
|
||||||
/>
|
/>
|
||||||
</InputBlock>
|
</InputBlock>
|
||||||
<InputBlock label={"Sprite URL"} doc={styleSpec.latest.$root.sprite.doc}>
|
<InputBlock label={"Sprite URL"} doc={styleSpec.latest.$root.sprite.doc}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.sprite"
|
||||||
value={this.props.mapStyle.sprite}
|
value={this.props.mapStyle.sprite}
|
||||||
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
onChange={this.changeStyleProperty.bind(this, "sprite")}
|
||||||
/>
|
/>
|
||||||
|
@ -68,6 +72,7 @@ class SettingsModal extends React.Component {
|
||||||
|
|
||||||
<InputBlock label={"Glyphs URL"} doc={styleSpec.latest.$root.glyphs.doc}>
|
<InputBlock label={"Glyphs URL"} doc={styleSpec.latest.$root.glyphs.doc}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.glyphs"
|
||||||
value={this.props.mapStyle.glyphs}
|
value={this.props.mapStyle.glyphs}
|
||||||
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
onChange={this.changeStyleProperty.bind(this, "glyphs")}
|
||||||
/>
|
/>
|
||||||
|
@ -75,6 +80,7 @@ class SettingsModal extends React.Component {
|
||||||
|
|
||||||
<InputBlock label={"Mapbox Access Token"} doc={"Public access token for Mapbox services."}>
|
<InputBlock label={"Mapbox Access Token"} doc={"Public access token for Mapbox services."}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.maputnik:mapbox_access_token"
|
||||||
value={metadata['maputnik:mapbox_access_token']}
|
value={metadata['maputnik:mapbox_access_token']}
|
||||||
onChange={this.changeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
|
onChange={this.changeMetadataProperty.bind(this, "maputnik:mapbox_access_token")}
|
||||||
/>
|
/>
|
||||||
|
@ -82,6 +88,7 @@ class SettingsModal extends React.Component {
|
||||||
|
|
||||||
<InputBlock label={"OpenMapTiles Access Token"} doc={"Public access token for the OpenMapTiles CDN."}>
|
<InputBlock label={"OpenMapTiles Access Token"} doc={"Public access token for the OpenMapTiles CDN."}>
|
||||||
<StringInput {...inputProps}
|
<StringInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.maputnik:openmaptiles_access_token"
|
||||||
value={metadata['maputnik:openmaptiles_access_token']}
|
value={metadata['maputnik:openmaptiles_access_token']}
|
||||||
onChange={this.changeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
onChange={this.changeMetadataProperty.bind(this, "maputnik:openmaptiles_access_token")}
|
||||||
/>
|
/>
|
||||||
|
@ -89,6 +96,7 @@ class SettingsModal extends React.Component {
|
||||||
|
|
||||||
<InputBlock label={"Style Renderer"} doc={"Choose the default Maputnik renderer for this style."}>
|
<InputBlock label={"Style Renderer"} doc={"Choose the default Maputnik renderer for this style."}>
|
||||||
<SelectInput {...inputProps}
|
<SelectInput {...inputProps}
|
||||||
|
data-wd-key="modal-settings.maputnik:renderer"
|
||||||
options={[
|
options={[
|
||||||
['mbgljs', 'MapboxGL JS'],
|
['mbgljs', 'MapboxGL JS'],
|
||||||
['ol3', 'Open Layers 3'],
|
['ol3', 'Open Layers 3'],
|
||||||
|
|
44
src/libs/debug.js
Normal file
44
src/libs/debug.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import querystring from 'querystring'
|
||||||
|
|
||||||
|
|
||||||
|
const debugStore = {};
|
||||||
|
|
||||||
|
function enabled() {
|
||||||
|
const qs = querystring.parse(window.location.search.slice(1));
|
||||||
|
if(qs.hasOwnProperty("debug")) {
|
||||||
|
return !!qs.debug.match(/^(|1|true)$/);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function genErr() {
|
||||||
|
return new Error("Debug not enabled, enable by appending '?debug' to your query string");
|
||||||
|
}
|
||||||
|
|
||||||
|
function set(namespace, key, value) {
|
||||||
|
if(!enabled()) {
|
||||||
|
throw genErr();
|
||||||
|
}
|
||||||
|
debugStore[namespace] = debugStore[namespace] || {};
|
||||||
|
debugStore[namespace][key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get(namespace, key) {
|
||||||
|
if(!enabled()) {
|
||||||
|
throw genErr();
|
||||||
|
}
|
||||||
|
if(debugStore.hasOwnProperty(namespace)) {
|
||||||
|
return debugStore[namespace][key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mod = {
|
||||||
|
enabled,
|
||||||
|
get,
|
||||||
|
set
|
||||||
|
}
|
||||||
|
|
||||||
|
window.debug = mod;
|
||||||
|
export default mod;
|
|
@ -37,3 +37,14 @@ $toolbar-offset: 0;
|
||||||
@import 'popup';
|
@import 'popup';
|
||||||
@import 'map';
|
@import 'map';
|
||||||
@import 'react-collapse';
|
@import 'react-collapse';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hacks for webdriverio isVisibleWithinViewport
|
||||||
|
*/
|
||||||
|
#app {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maputnik-layout {
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
39
test/artifacts.js
Normal file
39
test/artifacts.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
var path = require("path");
|
||||||
|
var mkdirp = require("mkdirp");
|
||||||
|
|
||||||
|
|
||||||
|
function genPath(subPath) {
|
||||||
|
subPath = subPath || ".";
|
||||||
|
var buildPath;
|
||||||
|
|
||||||
|
if(process.env.CIRCLECI) {
|
||||||
|
buildPath = path.join("/tmp/artifacts", subPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buildPath = path.join(__dirname, '..', 'build', subPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.path = function(subPath) {
|
||||||
|
var dirPath = genPath(subPath);
|
||||||
|
|
||||||
|
return new Promise(function(resolve, reject) {
|
||||||
|
mkdirp(dirPath, function(err) {
|
||||||
|
if(err) {
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(dirPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.pathSync = function(subPath) {
|
||||||
|
var dirPath = genPath(subPath);
|
||||||
|
mkdirp.sync(dirPath);
|
||||||
|
return dirPath;
|
||||||
|
}
|
||||||
|
|
12
test/example-style.json
Normal file
12
test/example-style.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"id": "test-style",
|
||||||
|
"version": 8,
|
||||||
|
"name": "Test Style",
|
||||||
|
"metadata": {
|
||||||
|
"maputnik:renderer": "mbgljs"
|
||||||
|
},
|
||||||
|
"sources": {},
|
||||||
|
"glyphs": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||||
|
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||||
|
"layers": []
|
||||||
|
}
|
77
test/functional/helper.js
Normal file
77
test/functional/helper.js
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
var wd = require("../wd-helper");
|
||||||
|
var uuid = require('uuid/v1');
|
||||||
|
var geoServer = require("../geojson-server");
|
||||||
|
|
||||||
|
|
||||||
|
var geoserver = geoServer.listen(9002);
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getStyleUrl: function(styles) {
|
||||||
|
var port = geoserver.address().port;
|
||||||
|
return "http://localhost:"+port+"/styles/empty/"+styles.join(",");
|
||||||
|
},
|
||||||
|
getGeoServerUrl: function(urlPath) {
|
||||||
|
var port = geoserver.address().port;
|
||||||
|
return "http://localhost:"+port+"/"+urlPath;
|
||||||
|
},
|
||||||
|
getStyleStore: function(browser) {
|
||||||
|
var result = browser.executeAsync(function(done) {
|
||||||
|
window.debug.get("maputnik", "styleStore").latestStyle(done);
|
||||||
|
})
|
||||||
|
return result.value;
|
||||||
|
},
|
||||||
|
getRevisionStore: function(browser) {
|
||||||
|
var result = browser.execute(function(done) {
|
||||||
|
var rs = window.debug.get("maputnik", "revisionStore")
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentIdx: rs.currentIdx,
|
||||||
|
revisions: rs.revisions
|
||||||
|
};
|
||||||
|
})
|
||||||
|
return result.value;
|
||||||
|
},
|
||||||
|
modal: {
|
||||||
|
addLayer: {
|
||||||
|
open: function() {
|
||||||
|
var selector = wd.$('layer-list:add-layer');
|
||||||
|
browser.click(selector);
|
||||||
|
|
||||||
|
// Wait for events
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.waitForExist(wd.$('modal:add-layer'));
|
||||||
|
browser.isVisible(wd.$('modal:add-layer'));
|
||||||
|
browser.isVisibleWithinViewport(wd.$('modal:add-layer'));
|
||||||
|
|
||||||
|
// Wait for events
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
},
|
||||||
|
fill: function(opts) {
|
||||||
|
var type = opts.type;
|
||||||
|
var layer = opts.layer;
|
||||||
|
var id;
|
||||||
|
if(opts.id) {
|
||||||
|
id = opts.id
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
id = type+":"+uuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.selectByValue(wd.$("add-layer.layer-type", "select"), type);
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.setValueSafe(wd.$("add-layer.layer-id", "input"), id);
|
||||||
|
if(layer) {
|
||||||
|
browser.setValueSafe(wd.$("add-layer.layer-source-block", "input"), layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
browser.click(wd.$("add-layer"));
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
100
test/functional/history/index.js
Normal file
100
test/functional/history/index.js
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
var assert = require("assert");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
|
||||||
|
|
||||||
|
describe.skip("history", function() {
|
||||||
|
/**
|
||||||
|
* See <https://github.com/webdriverio/webdriverio/issues/1126>
|
||||||
|
*/
|
||||||
|
it("undo/redo", function() {
|
||||||
|
var styleObj;
|
||||||
|
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
|
||||||
|
helper.modal.addLayer.open();
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, []);
|
||||||
|
|
||||||
|
helper.modal.addLayer.fill({
|
||||||
|
id: "step 1",
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": "step 1",
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
helper.modal.addLayer.open();
|
||||||
|
helper.modal.addLayer.fill({
|
||||||
|
id: "step 2",
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": "step 1",
|
||||||
|
"type": 'background'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step 2",
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser
|
||||||
|
.keys(['Control', 'z'])
|
||||||
|
.keys(['Control']);
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": "step 1",
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser
|
||||||
|
.keys(['Control', 'z'])
|
||||||
|
.keys(['Control']);
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser
|
||||||
|
.keys(['Control', 'y'])
|
||||||
|
.keys(['Control']);
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": "step 1",
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser
|
||||||
|
.keys(['Control', 'y'])
|
||||||
|
.keys(['Control']);
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": "step 1",
|
||||||
|
"type": 'background'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step 2",
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
33
test/functional/index.js
Normal file
33
test/functional/index.js
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var config = require("../config/specs");
|
||||||
|
var geoServer = require("../geojson-server");
|
||||||
|
var helper = require("./helper");
|
||||||
|
|
||||||
|
require("./util/webdriverio-ext");
|
||||||
|
|
||||||
|
|
||||||
|
describe('maputnik', function() {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example",
|
||||||
|
"raster:raster"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
});
|
||||||
|
|
||||||
|
// -------- setup --------
|
||||||
|
require("./util/coverage");
|
||||||
|
// -----------------------
|
||||||
|
|
||||||
|
// ---- All the tests ----
|
||||||
|
require("./history");
|
||||||
|
require("./layers");
|
||||||
|
require("./map");
|
||||||
|
require("./modals");
|
||||||
|
require("./screenshots");
|
||||||
|
// ------------------------
|
||||||
|
|
||||||
|
});
|
||||||
|
|
485
test/functional/layers/index.js
Normal file
485
test/functional/layers/index.js
Normal file
|
@ -0,0 +1,485 @@
|
||||||
|
var assert = require("assert");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
var uuid = require('uuid/v1');
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
|
||||||
|
|
||||||
|
describe("layers", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example",
|
||||||
|
"raster:raster"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
helper.modal.addLayer.open();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("ops", function() {
|
||||||
|
it("delete", function() {
|
||||||
|
var styleObj;
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": 'background'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:"+id+":delete", ""));
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("duplicate", function() {
|
||||||
|
var styleObj;
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": 'background'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:"+id+":copy", ""));
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id+"-copy",
|
||||||
|
"type": "background"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "background"
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("hide", function() {
|
||||||
|
var styleObj;
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": 'background'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:"+id+":toggle-visibility", ""));
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "background",
|
||||||
|
"layout": {
|
||||||
|
"visibility": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:"+id+":toggle-visibility", ""));
|
||||||
|
|
||||||
|
styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "background",
|
||||||
|
"layout": {
|
||||||
|
"visibility": "visible"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("grouped", function() {
|
||||||
|
it("with underscore")
|
||||||
|
it("no without underscore")
|
||||||
|
it("double underscore only grouped once")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("tooltips", function() {
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("help", function() {
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe('background', function () {
|
||||||
|
|
||||||
|
it.skip("add", function() {
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.waitUntil(function() {
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("modify", function() {
|
||||||
|
function createBackground() {
|
||||||
|
// Setup
|
||||||
|
var id = uuid();
|
||||||
|
|
||||||
|
browser.selectByValue(wd.$("add-layer.layer-type", "select"), "background");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
browser.setValueSafe(wd.$("add-layer.layer-id", "input"), "background:"+id);
|
||||||
|
|
||||||
|
browser.click(wd.$("add-layer"));
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": 'background:'+id,
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====> THESE SHOULD BE FROM THE SPEC
|
||||||
|
describe("layer", function() {
|
||||||
|
it("expand/collapse");
|
||||||
|
it("id", function() {
|
||||||
|
var bgId = createBackground();
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:background:"+bgId))
|
||||||
|
|
||||||
|
var id = uuid();
|
||||||
|
browser.setValueSafe(wd.$("layer-editor.layer-id", "input"), "foobar:"+id)
|
||||||
|
browser.click(wd.$("min-zoom"))
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": 'foobar:'+id,
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// NOTE: This needs to be removed from the code
|
||||||
|
it("type");
|
||||||
|
|
||||||
|
it("min-zoom", function() {
|
||||||
|
var bgId = createBackground();
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:background:"+bgId))
|
||||||
|
browser.setValueSafe(wd.$("min-zoom", "input"), 1)
|
||||||
|
browser.click(wd.$("layer-editor.layer-id", "input"));
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": 'background:'+bgId,
|
||||||
|
"type": 'background',
|
||||||
|
"minzoom": 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// AND RESET!
|
||||||
|
// browser.setValueSafe(wd.$("min-zoom", "input"), "")
|
||||||
|
// browser.click(wd.$("max-zoom", "input"));
|
||||||
|
|
||||||
|
// var styleObj = helper.getStyleStore(browser);
|
||||||
|
|
||||||
|
// assert.deepEqual(styleObj.layers, [
|
||||||
|
// {
|
||||||
|
// "id": 'background:'+bgId,
|
||||||
|
// "type": 'background'
|
||||||
|
// }
|
||||||
|
// ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("max-zoom", function() {
|
||||||
|
var bgId = createBackground();
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:background:"+bgId))
|
||||||
|
browser.setValueSafe(wd.$("max-zoom", "input"), 1)
|
||||||
|
browser.click(wd.$("layer-editor.layer-id", "input"));
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": 'background:'+bgId,
|
||||||
|
"type": 'background',
|
||||||
|
"maxzoom": 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("comments", function() {
|
||||||
|
var bgId = createBackground();
|
||||||
|
var id = uuid();
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
browser.setValueSafe(wd.$("layer-comment", "textarea"), id);
|
||||||
|
browser.click(wd.$("layer-editor.layer-id", "input"));
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": 'background:'+bgId,
|
||||||
|
"type": 'background',
|
||||||
|
metadata: {
|
||||||
|
'maputnik:comment': id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Unset it again.
|
||||||
|
// TODO: This fails
|
||||||
|
// browser.setValueSafe(wd.$("layer-comment", "textarea"), "");
|
||||||
|
// browser.click(wd.$("min-zoom", "input"));
|
||||||
|
// browser.flushReactUpdates();
|
||||||
|
|
||||||
|
// var styleObj = helper.getStyleStore(browser);
|
||||||
|
// assert.deepEqual(styleObj.layers, [
|
||||||
|
// {
|
||||||
|
// "id": 'background:'+bgId,
|
||||||
|
// "type": 'background'
|
||||||
|
// }
|
||||||
|
// ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("color", null, function() {
|
||||||
|
var bgId = createBackground();
|
||||||
|
var id = uuid();
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
|
||||||
|
browser.click(wd.$("spec-field:background-color", "input"))
|
||||||
|
// browser.debug();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": 'background:'+bgId,
|
||||||
|
"type": 'background'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("filter", function() {
|
||||||
|
it("expand/collapse");
|
||||||
|
it("compound filter");
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("paint", function() {
|
||||||
|
it("expand/collapse");
|
||||||
|
it("color");
|
||||||
|
it("pattern");
|
||||||
|
it("opacity");
|
||||||
|
})
|
||||||
|
// <=====
|
||||||
|
|
||||||
|
describe("json-editor", function() {
|
||||||
|
it("expand/collapse");
|
||||||
|
it("modify");
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
it.skip("parse error", function() {
|
||||||
|
var bgId = createBackground();
|
||||||
|
var id = uuid();
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-item:background:"+bgId));
|
||||||
|
|
||||||
|
var errorSelector = ".CodeMirror-lint-marker-error";
|
||||||
|
assert.equal(browser.isExisting(errorSelector), false);
|
||||||
|
|
||||||
|
browser.click(".CodeMirror")
|
||||||
|
browser.keys("\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013 {");
|
||||||
|
browser.waitForExist(errorSelector)
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-editor.layer-id"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fill', function () {
|
||||||
|
it.skip("add", function() {
|
||||||
|
// browser.debug();
|
||||||
|
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "fill",
|
||||||
|
layer: "example"
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": 'fill',
|
||||||
|
"source": "example"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: Change source
|
||||||
|
it("change source")
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('line', function () {
|
||||||
|
it.skip("add", function() {
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "line",
|
||||||
|
layer: "example"
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "line",
|
||||||
|
"source": "example",
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("groups", null, function() {
|
||||||
|
// TODO
|
||||||
|
// Click each of the layer groups.
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('symbol', function () {
|
||||||
|
it.skip("add", function() {
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "symbol",
|
||||||
|
layer: "example"
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "symbol",
|
||||||
|
"source": "example",
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('raster', function () {
|
||||||
|
it.skip("add", function() {
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "raster",
|
||||||
|
layer: "raster"
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "raster",
|
||||||
|
"source": "raster",
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('circle', function () {
|
||||||
|
it.skip("add", function() {
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "circle",
|
||||||
|
layer: "example"
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "circle",
|
||||||
|
"source": "example",
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fill extrusion', function () {
|
||||||
|
it.skip("add", function() {
|
||||||
|
var id = helper.modal.addLayer.fill({
|
||||||
|
type: "fill-extrusion",
|
||||||
|
layer: "example"
|
||||||
|
});
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleObj.layers, [
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": 'fill-extrusion',
|
||||||
|
"source": "example"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe.skip("groups", function() {
|
||||||
|
it("simple", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
|
||||||
|
helper.modal.addLayer.open();
|
||||||
|
var aId = helper.modal.addLayer.fill({
|
||||||
|
id: "foo",
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.modal.addLayer.open();
|
||||||
|
var bId = helper.modal.addLayer.fill({
|
||||||
|
id: "foo_bar",
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
helper.modal.addLayer.open();
|
||||||
|
var bId = helper.modal.addLayer.fill({
|
||||||
|
id: "foo_baz",
|
||||||
|
type: "background"
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.waitForExist(wd.$("layer-list-group:foo-0"));
|
||||||
|
|
||||||
|
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo")), false);
|
||||||
|
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_bar")), false);
|
||||||
|
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_baz")), false);
|
||||||
|
|
||||||
|
browser.click(wd.$("layer-list-group:foo-0"));
|
||||||
|
|
||||||
|
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo")), true);
|
||||||
|
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_bar")), true);
|
||||||
|
assert.equal(browser.isVisibleWithinViewport(wd.$("layer-list-item:foo_baz")), true);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
35
test/functional/map/index.js
Normal file
35
test/functional/map/index.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
|
||||||
|
|
||||||
|
describe("map", function() {
|
||||||
|
describe.skip("zoom level", function() {
|
||||||
|
it("via url", function() {
|
||||||
|
var zoomLevel = "12.37"
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
])+"#"+zoomLevel+"/41.3805/2.1635");
|
||||||
|
|
||||||
|
browser.waitUntil(function () {
|
||||||
|
return (
|
||||||
|
browser.isVisible(".mapboxgl-ctrl-zoom")
|
||||||
|
&& browser.getText(".mapboxgl-ctrl-zoom") === "Zoom level: "+(zoomLevel)
|
||||||
|
);
|
||||||
|
}, 10*1000)
|
||||||
|
})
|
||||||
|
it("via map controls", function() {
|
||||||
|
var zoomLevel = 12.37;
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
])+"#"+zoomLevel+"/41.3805/2.1635");
|
||||||
|
|
||||||
|
browser.click(".mapboxgl-ctrl-zoom-in")
|
||||||
|
browser.waitUntil(function () {
|
||||||
|
var text = browser.getText(".mapboxgl-ctrl-zoom")
|
||||||
|
return text === "Zoom level: "+(zoomLevel+1);
|
||||||
|
}, 10*1000)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
188
test/functional/modals/index.js
Normal file
188
test/functional/modals/index.js
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
var fs = require("fs");
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
|
||||||
|
|
||||||
|
function closeModal(wdKey) {
|
||||||
|
browser.waitUntil(function() {
|
||||||
|
return browser.isVisibleWithinViewport(wd.$(wdKey));
|
||||||
|
});
|
||||||
|
|
||||||
|
var closeBtnSelector = wd.$(wdKey+".close-modal");
|
||||||
|
browser.click(closeBtnSelector);
|
||||||
|
|
||||||
|
browser.waitUntil(function() {
|
||||||
|
return !browser.isVisibleWithinViewport(wd.$(wdKey));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("modals", function() {
|
||||||
|
describe("open", function() {
|
||||||
|
var styleFilePath = __dirname+"/../../example-style.json";
|
||||||
|
var styleFileData = JSON.parse(fs.readFileSync(styleFilePath));
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:open"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("close", function() {
|
||||||
|
closeModal("open-modal");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("upload", function() {
|
||||||
|
browser.waitForExist("*[type='file']")
|
||||||
|
browser.chooseFile("*[type='file']", styleFilePath);
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleFileData, styleObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("load from url", function() {
|
||||||
|
var styleFileUrl = helper.getGeoServerUrl("example-style.json");
|
||||||
|
|
||||||
|
browser.setValueSafe(wd.$("open-modal.url.input"), styleFileUrl);
|
||||||
|
|
||||||
|
var selector = wd.$("open-modal.url.button");
|
||||||
|
browser.click(selector);
|
||||||
|
|
||||||
|
// Allow the network request to happen
|
||||||
|
// NOTE: Its localhost so this should be fast.
|
||||||
|
browser.pause(300);
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.deepEqual(styleFileData, styleObj);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Need to work out how to mock out the end points
|
||||||
|
it("gallery")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("export", function() {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:export"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("close", function() {
|
||||||
|
closeModal("export-modal");
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Work out how to download a file and check the contents
|
||||||
|
it("download")
|
||||||
|
|
||||||
|
// TODO: Work out how to mock the end git points
|
||||||
|
it("save to gist")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("sources", function() {
|
||||||
|
it("active sources")
|
||||||
|
it("public source")
|
||||||
|
it("add new source")
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("inspect", function() {
|
||||||
|
it("toggle", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:inspect"));
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("style settings", function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.url(config.baseUrl+"?debug");
|
||||||
|
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:settings"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("name", function() {
|
||||||
|
browser.setValueSafe(wd.$("modal-settings.name"), "foobar")
|
||||||
|
browser.click(wd.$("modal-settings.owner"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.equal(styleObj.name, "foobar");
|
||||||
|
})
|
||||||
|
it("owner", function() {
|
||||||
|
browser.setValueSafe(wd.$("modal-settings.owner"), "foobar")
|
||||||
|
browser.click(wd.$("modal-settings.name"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.equal(styleObj.owner, "foobar");
|
||||||
|
})
|
||||||
|
it("sprite url", function() {
|
||||||
|
browser.setValueSafe(wd.$("modal-settings.sprite"), "http://example.com")
|
||||||
|
browser.click(wd.$("modal-settings.name"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.equal(styleObj.sprite, "http://example.com");
|
||||||
|
})
|
||||||
|
it("glyphs url", function() {
|
||||||
|
var glyphsUrl = "http://example.com/{fontstack}/{range}.pbf"
|
||||||
|
browser.setValueSafe(wd.$("modal-settings.glyphs"), glyphsUrl)
|
||||||
|
browser.click(wd.$("modal-settings.name"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.equal(styleObj.glyphs, glyphsUrl);
|
||||||
|
})
|
||||||
|
|
||||||
|
it("mapbox access token", function() {
|
||||||
|
var apiKey = "testing123";
|
||||||
|
browser.setValueSafe(wd.$("modal-settings.maputnik:mapbox_access_token"), apiKey);
|
||||||
|
browser.click(wd.$("modal-settings.name"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
browser.waitUntil(function() {
|
||||||
|
return styleObj.metadata["maputnik:mapbox_access_token"] == apiKey;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("open map tiles access token", function() {
|
||||||
|
var apiKey = "testing123";
|
||||||
|
browser.setValueSafe(wd.$("modal-settings.maputnik:openmaptiles_access_token"), apiKey);
|
||||||
|
browser.click(wd.$("modal-settings.name"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.equal(styleObj.metadata["maputnik:openmaptiles_access_token"], apiKey);
|
||||||
|
})
|
||||||
|
|
||||||
|
it("style renderer", function() {
|
||||||
|
var selector = wd.$("modal-settings.maputnik:renderer");
|
||||||
|
browser.selectByValue(selector, "ol3");
|
||||||
|
browser.click(wd.$("modal-settings.name"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
var styleObj = helper.getStyleStore(browser);
|
||||||
|
assert.equal(styleObj.metadata["maputnik:renderer"], "ol3");
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("sources", function() {
|
||||||
|
it("toggle")
|
||||||
|
})
|
||||||
|
})
|
93
test/functional/screenshots/index.js
Normal file
93
test/functional/screenshots/index.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
var artifacts = require("../../artifacts");
|
||||||
|
var config = require("../../config/specs");
|
||||||
|
var helper = require("../helper");
|
||||||
|
var wd = require("../../wd-helper");
|
||||||
|
|
||||||
|
|
||||||
|
// These will get used in the marketing material. They are also useful to do a quick manual check of the styling across browsers
|
||||||
|
// NOTE: These duplicate some of the tests, however this is indended becuase it's likely these will change for aesthetic reasons over time
|
||||||
|
describe('screenshots', function() {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
browser.windowHandleSize({
|
||||||
|
width: 1280,
|
||||||
|
height: 800
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
it("front_page", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.takeScreenShot("/front_page.png")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("open", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:open"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.takeScreenShot("/open.png")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("export", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:export"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.takeScreenShot("/export.png")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sources", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:sources"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.takeScreenShot("/sources.png")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("style settings", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:settings"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.takeScreenShot("/settings.png")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("inspect", function() {
|
||||||
|
browser.url(config.baseUrl+"?debug&style="+helper.getStyleUrl([
|
||||||
|
"geojson:example"
|
||||||
|
]));
|
||||||
|
browser.waitForExist(".maputnik-toolbar-link");
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.click(wd.$("nav:inspect"))
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
|
||||||
|
browser.takeScreenShot("/inspect.png")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
24
test/functional/util/coverage.js
Normal file
24
test/functional/util/coverage.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
var artifacts = require("../../artifacts");
|
||||||
|
var fs = require("fs");
|
||||||
|
var istanbulCov = require('istanbul-lib-coverage');
|
||||||
|
|
||||||
|
var COVERAGE_PATH = artifacts.pathSync("/coverage");
|
||||||
|
|
||||||
|
|
||||||
|
var coverage = istanbulCov.createCoverageMap({});
|
||||||
|
|
||||||
|
// Capture the coverage after each test
|
||||||
|
afterEach(function() {
|
||||||
|
// Code coverage
|
||||||
|
var results = browser.execute(function() {
|
||||||
|
return window.__coverage__;
|
||||||
|
});
|
||||||
|
|
||||||
|
coverage.merge(results.value);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Dump the coverage to a file
|
||||||
|
after(function() {
|
||||||
|
var jsonStr = JSON.stringify(coverage, null, 2);
|
||||||
|
fs.writeFileSync(COVERAGE_PATH+"/coverage.json", jsonStr);
|
||||||
|
})
|
58
test/functional/util/webdriverio-ext.js
Normal file
58
test/functional/util/webdriverio-ext.js
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
var artifacts = require("../../artifacts");
|
||||||
|
var fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
|
||||||
|
|
||||||
|
browser.timeoutsAsyncScript(20*1000);
|
||||||
|
browser.timeoutsImplicitWait(20*1000);
|
||||||
|
|
||||||
|
var SCREENSHOTS_PATH = artifacts.pathSync("/screenshots");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sometimes chrome driver can result in the wrong text.
|
||||||
|
*
|
||||||
|
* See <https://github.com/webdriverio/webdriverio/issues/1886>
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
browser.addCommand('setValueSafe', function(selector, text) {
|
||||||
|
for(var i=0; i<10; i++) {
|
||||||
|
browser.waitForVisible(selector);
|
||||||
|
|
||||||
|
var elements = browser.elements(selector);
|
||||||
|
if(elements.length > 1) {
|
||||||
|
throw "Too many elements found";
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.setValue(selector, text);
|
||||||
|
var browserText = browser.getValue(selector);
|
||||||
|
|
||||||
|
if(browserText == text) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error("Warning: setValue failed, trying again");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for change events to fire and state updated
|
||||||
|
browser.flushReactUpdates();
|
||||||
|
})
|
||||||
|
|
||||||
|
browser.addCommand('takeScreenShot', function(filepath) {
|
||||||
|
var data = browser.screenshot();
|
||||||
|
fs.writeFileSync(path.join(SCREENSHOTS_PATH, filepath), data.value, 'base64');
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.addCommand('flushReactUpdates', function() {
|
||||||
|
browser.executeAsync(function(done) {
|
||||||
|
// For any events to propogate
|
||||||
|
setImmediate(function() {
|
||||||
|
// For the DOM to be updated.
|
||||||
|
setImmediate(done);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
console.error(">>> Ignored error: "+err);
|
||||||
|
}
|
90
test/geojson-server.js
Normal file
90
test/geojson-server.js
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
const cors = require("cors");
|
||||||
|
const express = require("express");
|
||||||
|
const fs = require("fs");
|
||||||
|
const sourceData = require("./sources");
|
||||||
|
|
||||||
|
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
|
|
||||||
|
function buildStyle(opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
opts = Object.assign({
|
||||||
|
sources: {}
|
||||||
|
}, opts);
|
||||||
|
|
||||||
|
return {
|
||||||
|
"id": "test-style",
|
||||||
|
"version": 8,
|
||||||
|
"name": "Test Style",
|
||||||
|
"metadata": {
|
||||||
|
"maputnik:renderer": "mbgljs"
|
||||||
|
},
|
||||||
|
"sources": opts.sources,
|
||||||
|
"glyphs": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||||
|
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||||
|
"layers": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildGeoJSONSource(data) {
|
||||||
|
return {
|
||||||
|
type: "vector",
|
||||||
|
data: data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildResterSource(req, key) {
|
||||||
|
return {
|
||||||
|
"tileSize": 256,
|
||||||
|
"tiles": [
|
||||||
|
req.protocol + '://' + req.get('host') + "/" + key + "/{x}/{y}/{z}"
|
||||||
|
],
|
||||||
|
"type": "raster"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
app.get("/sources/raster/{x}/{y}/{z}", function(req, res) {
|
||||||
|
res.status(404).end();
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get("/styles/empty/:sources", function(req, res) {
|
||||||
|
var reqSources = req.params.sources.split(",");
|
||||||
|
|
||||||
|
var sources = {};
|
||||||
|
reqSources.forEach(function(key) {
|
||||||
|
var parts = key.split(":");
|
||||||
|
var type = parts[0];
|
||||||
|
var key = parts[1];
|
||||||
|
|
||||||
|
if(type === "geojson") {
|
||||||
|
sources[key] = buildGeoJSONSource(sourceData[key]);
|
||||||
|
}
|
||||||
|
else if(type === "raster") {
|
||||||
|
sources[key] = buildResterSource(req, key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error("ERR: Invalid type: %s", type);
|
||||||
|
throw "Invalid type"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var json = buildStyle({
|
||||||
|
sources: sources
|
||||||
|
});
|
||||||
|
res.send(json);
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get("/example-style.json", function(req, res) {
|
||||||
|
res.json(
|
||||||
|
JSON.parse(
|
||||||
|
fs.readFileSync(__dirname+"/example-style.json").toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = app;
|
15
test/sources/example.json
Normal file
15
test/sources/example.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"type":"FeatureCollection",
|
||||||
|
"features":[
|
||||||
|
{
|
||||||
|
"type":"Feature",
|
||||||
|
"properties": {
|
||||||
|
"name": "Dinagat Islands"
|
||||||
|
},
|
||||||
|
"geometry":{
|
||||||
|
"type": "Point",
|
||||||
|
"coordinates": [125.6, 10.1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
3
test/sources/index.js
Normal file
3
test/sources/index.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
example: require("./example")
|
||||||
|
};
|
|
@ -1,15 +0,0 @@
|
||||||
var assert = require('assert');
|
|
||||||
var config = require("../config/specs");
|
|
||||||
|
|
||||||
|
|
||||||
describe('maputnik', function() {
|
|
||||||
|
|
||||||
it('check logo exists', function () {
|
|
||||||
browser.url(config.baseUrl);
|
|
||||||
browser.waitForExist(".maputnik-toolbar-link");
|
|
||||||
|
|
||||||
var src = browser.getAttribute(".maputnik-toolbar-link img", "src");
|
|
||||||
assert.equal(src, config.baseUrl+'/img/logo-color.svg');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
6
test/wd-helper.js
Normal file
6
test/wd-helper.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
"$": function(key, selector) {
|
||||||
|
selector = selector || "";
|
||||||
|
return "*[data-wd-key='"+key+"'] "+selector;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue