mirror of
https://github.com/maputnik/editor.git
synced 2026-01-09 23:10:01 +00:00
Replace WebDriverIO with Cypress (#831)
This does the following: 1. Moves the WDIO code from javascript to typescript 2. Moves to use files that are `cy.ts` instead of `index.js` 3. Replace e2e to use cypress 4. Introduce back some skipped tests This is in continue to the conversation here: https://github.com/HarelM/editor/pull/3 Before: ``` "spec" Reporter: ------------------------------------------------------------------ [chrome 120.0.6099.71 linux #0-0] Running: chrome (v120.0.6099.71) on linux [chrome 120.0.6099.71 linux #0-0] Session ID: ee9a87bcfce007ac7721929c6e6234d0 [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] » /test/functional/index.js [chrome 120.0.6099.71 linux #0-0] maputnik [chrome 120.0.6099.71 linux #0-0] history [chrome 120.0.6099.71 linux #0-0] - undo/redo [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] layers [chrome 120.0.6099.71 linux #0-0] ops [chrome 120.0.6099.71 linux #0-0] ✓ delete [chrome 120.0.6099.71 linux #0-0] ✓ duplicate [chrome 120.0.6099.71 linux #0-0] ✓ hide [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] background [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] modify [chrome 120.0.6099.71 linux #0-0] layer [chrome 120.0.6099.71 linux #0-0] - expand/collapse [chrome 120.0.6099.71 linux #0-0] ✓ id [chrome 120.0.6099.71 linux #0-0] ✓ min-zoom [chrome 120.0.6099.71 linux #0-0] ✓ max-zoom [chrome 120.0.6099.71 linux #0-0] ✓ comments [chrome 120.0.6099.71 linux #0-0] - color [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] filter [chrome 120.0.6099.71 linux #0-0] - expand/collapse [chrome 120.0.6099.71 linux #0-0] - compound filter [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] paint [chrome 120.0.6099.71 linux #0-0] - expand/collapse [chrome 120.0.6099.71 linux #0-0] - color [chrome 120.0.6099.71 linux #0-0] - pattern [chrome 120.0.6099.71 linux #0-0] - opacity [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] json-editor [chrome 120.0.6099.71 linux #0-0] - expand/collapse [chrome 120.0.6099.71 linux #0-0] - modify [chrome 120.0.6099.71 linux #0-0] - parse error [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] fill [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] - change source [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] line [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] - groups [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] symbol [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] raster [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] circle [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] fill extrusion [chrome 120.0.6099.71 linux #0-0] ✓ add [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] groups [chrome 120.0.6099.71 linux #0-0] ✓ simple [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] map [chrome 120.0.6099.71 linux #0-0] zoom level [chrome 120.0.6099.71 linux #0-0] - via url [chrome 120.0.6099.71 linux #0-0] - via map controls [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] modals [chrome 120.0.6099.71 linux #0-0] open [chrome 120.0.6099.71 linux #0-0] ✓ close [chrome 120.0.6099.71 linux #0-0] - upload [chrome 120.0.6099.71 linux #0-0] ✓ load from url [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] shortcuts [chrome 120.0.6099.71 linux #0-0] ✓ open/close [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] export [chrome 120.0.6099.71 linux #0-0] ✓ close [chrome 120.0.6099.71 linux #0-0] - download [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] sources [chrome 120.0.6099.71 linux #0-0] - active sources [chrome 120.0.6099.71 linux #0-0] - public source [chrome 120.0.6099.71 linux #0-0] - add new source [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] inspect [chrome 120.0.6099.71 linux #0-0] ✓ toggle [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] style settings [chrome 120.0.6099.71 linux #0-0] ✓ name [chrome 120.0.6099.71 linux #0-0] ✓ owner [chrome 120.0.6099.71 linux #0-0] ✓ sprite url [chrome 120.0.6099.71 linux #0-0] ✓ glyphs url [chrome 120.0.6099.71 linux #0-0] ✓ maptiler access token [chrome 120.0.6099.71 linux #0-0] ✓ thunderforest access token [chrome 120.0.6099.71 linux #0-0] ✓ style renderer [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] sources [chrome 120.0.6099.71 linux #0-0] - toggle [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] screenshots [chrome 120.0.6099.71 linux #0-0] ✓ front_page [chrome 120.0.6099.71 linux #0-0] ✓ open [chrome 120.0.6099.71 linux #0-0] ✓ export [chrome 120.0.6099.71 linux #0-0] ✓ sources [chrome 120.0.6099.71 linux #0-0] ✓ style settings [chrome 120.0.6099.71 linux #0-0] ✓ inspect [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] accessibility [chrome 120.0.6099.71 linux #0-0] skip links [chrome 120.0.6099.71 linux #0-0] ✓ skip link to layer list [chrome 120.0.6099.71 linux #0-0] ✓ skip link to layer editor [chrome 120.0.6099.71 linux #0-0] ✓ skip link to map view [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] keyboard [chrome 120.0.6099.71 linux #0-0] shortcuts [chrome 120.0.6099.71 linux #0-0] ✓ ESC should unfocus [chrome 120.0.6099.71 linux #0-0] ✓ '?' should show shortcuts modal [chrome 120.0.6099.71 linux #0-0] ✓ 'o' should show open modal [chrome 120.0.6099.71 linux #0-0] ✓ 'e' should show export modal [chrome 120.0.6099.71 linux #0-0] ✓ 'd' should show sources modal [chrome 120.0.6099.71 linux #0-0] ✓ 's' should show settings modal [chrome 120.0.6099.71 linux #0-0] - 'i' should change map to inspect mode [chrome 120.0.6099.71 linux #0-0] ✓ 'm' should focus map [chrome 120.0.6099.71 linux #0-0] ✓ '!' should show debug modal [chrome 120.0.6099.71 linux #0-0] [chrome 120.0.6099.71 linux #0-0] 44 passing (58.8s) [chrome 120.0.6099.71 linux #0-0] 23 skipped ``` After: ``` accessibility skip links - skip link to layer list - skip link to layer editor - skip link to map view history ✓ undo/redo (4894ms) keyboard shortcuts ✓ ESC should unfocus (1912ms) ✓ '?' should show shortcuts modal (458ms) ✓ 'o' should show open modal (710ms) ✓ 'e' should show export modal (692ms) ✓ 'd' should show sources modal (588ms) ✓ 's' should show settings modal (894ms) ✓ 'i' should change map to inspect mode (804ms) ✓ 'm' should focus map (837ms) ✓ '!' should show debug modal (607ms) layers ops ✓ delete (4313ms) ✓ duplicate (1780ms) ✓ hide (1862ms) background ✓ add (1675ms) modify layer - expand/collapse ✓ id (3735ms) ✓ min-zoom (2209ms) ✓ max-zoom (2127ms) ✓ comments (2515ms) ✓ color (2022ms) filter - expand/collapse - compound filter paint - expand/collapse - color - pattern - opacity json-editor - expand/collapse - modify - parse error fill ✓ add (1831ms) - change source line ✓ add (1844ms) ✓ groups (687ms) symbol ✓ add (2035ms) raster ✓ add (1814ms) circle ✓ add (1867ms) fill extrusion ✓ add (1963ms) groups ✓ simple (2653ms) map zoom level ✓ via url (2279ms) ✓ via map controls (733ms) modals open ✓ close (2519ms) - upload ✓ load from url (1557ms) shortcuts ✓ open/close (1136ms) export ✓ close (755ms) - download sources - active sources - public source - add new source inspect ✓ toggle (1020ms) style settings ✓ name (1085ms) ✓ owner (1060ms) ✓ sprite url (1214ms) ✓ glyphs url (1553ms) ✓ maptiler access token (1111ms) ✓ thunderforest access token (1102ms) ✓ style renderer (922ms) sources - toggle Spec Tests Passing Failing Pending Skipped ┌────────────────────────────────────────────────────────────────────────────────────────────────┐ │ ✔ accessibility.cy.ts 52ms 3 - - 3 - │ ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ✔ history.cy.ts 00:06 1 1 - - - │ ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ✔ keyboard.cy.ts 00:10 9 9 - - - │ ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ✔ layers.cy.ts 00:39 28 17 - 11 - │ ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ✔ map.cy.ts 00:04 2 2 - - - │ ├────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ✔ modals.cy.ts 00:16 18 12 - 6 - │ └────────────────────────────────────────────────────────────────────────────────────────────────┘ ✔ All specs passed! 01:18 61 41 - 20 - ``` --------- Co-authored-by: Yuri Astrakhan <yuriastrakhan@gmail.com>
This commit is contained in:
55
.github/workflows/ci.yml
vendored
55
.github/workflows/ci.yml
vendored
@@ -141,52 +141,21 @@ jobs:
|
||||
with:
|
||||
name: maputnik-windows
|
||||
path: ./src/github.com/maputnik/desktop/bin/windows/
|
||||
|
||||
# build and test the editor
|
||||
test_selenium_standalone:
|
||||
name: "test/standalone-${{ matrix.browser }} (${{ matrix.os }})"
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' }}
|
||||
|
||||
|
||||
cypress-run:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
node-version: [18]
|
||||
browser: [chrome, firefox]
|
||||
|
||||
container:
|
||||
image: node:${{ matrix.node-version }}
|
||||
options: --network-alias testhost
|
||||
|
||||
services:
|
||||
selenium:
|
||||
image: selenium/standalone-${{ matrix.browser }}
|
||||
ports:
|
||||
- 4444:4444
|
||||
options: --shm-size=2gb
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
- run: npm ci
|
||||
- run: BROWSER=${{ matrix.browser }} TEST_NETWORK=testhost DOCKER_HOST=selenium npm run test
|
||||
- if: ${{ matrix.browser == 'chrome' }}
|
||||
run: ./node_modules/.bin/istanbul report --include build/coverage/coverage.json --dir build/coverage html lcov
|
||||
- if: ${{ matrix.browser == 'chrome' }}
|
||||
name: artifacts/coverage
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: coverage
|
||||
path: build/coverage
|
||||
- name: artifacts/screenshots
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: screenshots-${{ matrix.browser }}
|
||||
path: build/screenshots
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- run: npm ci
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@v6
|
||||
with:
|
||||
build: npm run build
|
||||
start: npm run start
|
||||
browser: ${{ matrix.browser }}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ public
|
||||
/errorShots
|
||||
/old
|
||||
/build
|
||||
/cypress/screenshots
|
||||
|
||||
17
README.md
17
README.md
@@ -76,9 +76,9 @@ npm run lint-styles
|
||||
|
||||
|
||||
## Tests
|
||||
For testing we use [webdriverio](https://webdriver.io) and [selenium-standalone](https://github.com/webdriverio/selenium-standalone).
|
||||
For E2E testing we use [Cypress](https://www.cypress.io/)
|
||||
|
||||
[selenium-standalone](https://github.com/webdriverio/selenium-standalone) starts a server that will launch browsers on your local machine. You need to have Java installed on your machine as well as *chrome* or *firefox*.
|
||||
[Cypress](https://www.cypress.io/) doesn't starts a server so you'll need to start one manually by running `npm run start`.
|
||||
|
||||
Now open a terminal and run the following using *chrome*:
|
||||
|
||||
@@ -87,10 +87,16 @@ npm run test
|
||||
```
|
||||
or *firefox*:
|
||||
```
|
||||
BROWSER=firefox npm run test
|
||||
npm run test -- --browser firefox
|
||||
```
|
||||
|
||||
After some time you should see a browser launch which will be automated by the test runner.
|
||||
See the following docs for more info: (Launching Browsers)[https://docs.cypress.io/guides/guides/launching-browsers]
|
||||
|
||||
You can also see the tests as they run or select which suites to run by executing:
|
||||
|
||||
```
|
||||
npm run cy:open
|
||||
```
|
||||
|
||||
|
||||
## Related Projects
|
||||
@@ -155,6 +161,5 @@ Sina Martinelli, Nicholas Doiron, Neil Cawse, Urs42, Benedikt Groß, Manuel Roth
|
||||
|
||||
Maputnik is [licensed under MIT](LICENSE) and is Copyright (c) Lukas Martinelli and contributors.
|
||||
|
||||
**Disclaimer** This project is not affiliated with Mapbox or Mapbox Studio. It is an independent style editor for the
|
||||
open source technology in the Mapbox GL ecosystem.
|
||||
**Disclaimer** This is an independent style editor.
|
||||
As contributor please take extra care of not violating any Mapbox trademarks. Do not get inspired by Mapbox Studio and make your own decisions for a good style editor.
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
var webpack = require("webpack");
|
||||
var WebpackDevServer = require("webpack-dev-server");
|
||||
var webpackConfig = require("./webpack.config");
|
||||
var testConfig = require("../test/config/specs");
|
||||
var artifacts = require("../test/artifacts");
|
||||
|
||||
|
||||
var server;
|
||||
var SCREENSHOT_PATH = artifacts.pathSync("screenshots");
|
||||
|
||||
exports.config = {
|
||||
runner: 'local',
|
||||
path: '/wd/hub',
|
||||
|
||||
specs: [
|
||||
'./test/functional/index.js'
|
||||
],
|
||||
maxInstances: 10,
|
||||
capabilities: [
|
||||
{
|
||||
maxInstances: 5,
|
||||
browserName: (process.env.BROWSER || 'chrome'),
|
||||
'goog:chromeOptions': {
|
||||
args: ['headless=new']
|
||||
}
|
||||
}
|
||||
],
|
||||
// geckodriver-0.31 seems to have problems as of 2022 May 1
|
||||
services: process.env.DOCKER_HOST ? [] : [ ['selenium-standalone', { drivers: { firefox: 'latest', chrome: 'latest' } } ] ],
|
||||
logLevel: 'warn',
|
||||
bail: 0,
|
||||
screenshotPath: SCREENSHOT_PATH,
|
||||
hostname: process.env.DOCKER_HOST || "0.0.0.0",
|
||||
framework: 'mocha',
|
||||
reporters: ['spec'],
|
||||
mochaOpts: {
|
||||
ui: 'bdd',
|
||||
// Because we don't know how long the initial build will take...
|
||||
timeout: 4*60*1000,
|
||||
},
|
||||
onPrepare: async function (config, capabilities) {
|
||||
webpackConfig.devServer.host = testConfig.testNetwork;
|
||||
webpackConfig.devServer.port = testConfig.port;
|
||||
const compiler = webpack(webpackConfig);
|
||||
server = new WebpackDevServer(webpackConfig.devServer, compiler);
|
||||
await server.start();
|
||||
},
|
||||
onComplete: async function (exitCode, config, capabilities) {
|
||||
await server.stop();
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,14 @@ var HtmlWebpackInlineSVGPlugin = require('html-webpack-inline-svg-plugin');
|
||||
var WebpackCleanupPlugin = require('webpack-cleanup-plugin');
|
||||
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
var CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
var artifacts = require("../test/artifacts");
|
||||
|
||||
var OUTPATH = artifacts.pathSync("/build");
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
app: './src/index.jsx',
|
||||
},
|
||||
output: {
|
||||
path: OUTPATH,
|
||||
path: path.join(__dirname, '..', 'build', 'build'),
|
||||
filename: '[name].[contenthash].js',
|
||||
chunkFilename: '[contenthash].js'
|
||||
},
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
const webpackProdConfig = require('./webpack.production.config');
|
||||
const artifacts = require("../test/artifacts");
|
||||
|
||||
const OUTPATH = artifacts.pathSync("/profiling");
|
||||
var path = require('path');
|
||||
|
||||
module.exports = {
|
||||
...webpackProdConfig,
|
||||
output: {
|
||||
...webpackProdConfig.output,
|
||||
path: OUTPATH,
|
||||
path: path.join(__dirname, '..', 'build', 'profiling'),
|
||||
},
|
||||
resolve: {
|
||||
...webpackProdConfig.resolve,
|
||||
|
||||
9
cypress.config.ts
Normal file
9
cypress.config.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from "cypress";
|
||||
|
||||
export default defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
});
|
||||
41
cypress/e2e/accessibility.cy.ts
Normal file
41
cypress/e2e/accessibility.cy.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import driver from "./driver";
|
||||
|
||||
describe("accessibility", () => {
|
||||
// skipped due to the following issue with cypress: https://github.com/cypress-io/cypress/issues/299
|
||||
describe.skip("skip links", () => {
|
||||
beforeEach(() => {
|
||||
driver.beforeEach();
|
||||
driver.setStyle("layer");
|
||||
});
|
||||
|
||||
it("skip link to layer list", () => {
|
||||
const selector = driver.getDataAttribute("root:skip:layer-list");
|
||||
driver.isExists(selector);
|
||||
driver.typeKeys('{tab}');
|
||||
driver.isFocused(selector);
|
||||
driver.click(selector);
|
||||
|
||||
driver.isFocused("#skip-target-layer-list");
|
||||
});
|
||||
|
||||
it("skip link to layer editor", () => {
|
||||
const selector = driver.getDataAttribute("root:skip:layer-editor");
|
||||
driver.isExists(selector);
|
||||
driver.typeKeys('{tab}{tab}');
|
||||
driver.isFocused(selector);
|
||||
driver.click(selector);
|
||||
|
||||
driver.isFocused("#skip-target-layer-editor");
|
||||
});
|
||||
|
||||
it("skip link to map view", () => {
|
||||
const selector = driver.getDataAttribute("root:skip:map-view");
|
||||
driver.isExists(selector);
|
||||
driver.typeKeys('{tab}{tab}{tab}');
|
||||
driver.isFocused(selector);
|
||||
driver.click(selector);
|
||||
|
||||
driver.isFocused(".maplibregl-canvas");
|
||||
});
|
||||
});
|
||||
})
|
||||
170
cypress/e2e/driver.ts
Normal file
170
cypress/e2e/driver.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import {v1 as uuid} from "uuid";
|
||||
|
||||
export default {
|
||||
isMac() {
|
||||
return Cypress.platform === "darwin";
|
||||
},
|
||||
|
||||
beforeEach() {
|
||||
this.setupInterception();
|
||||
this.setStyle('both');
|
||||
},
|
||||
|
||||
setupInterception() {
|
||||
cy.intercept('GET', 'http://localhost:8888/example-style.json', { fixture: 'example-style.json' }).as('example-style.json');
|
||||
cy.intercept('GET', 'http://localhost:8888/example-layer-style.json', { fixture: 'example-layer-style.json' });
|
||||
cy.intercept('GET', 'http://localhost:8888/geojson-style.json', { fixture: 'geojson-style.json' });
|
||||
cy.intercept('GET', 'http://localhost:8888/raster-style.json', { fixture: 'raster-style.json' });
|
||||
cy.intercept('GET', 'http://localhost:8888/geojson-raster-style.json', { fixture: 'geojson-raster-style.json' });
|
||||
cy.intercept({method: 'GET', url: '*example.local/*' }, []);
|
||||
cy.intercept({method: 'GET', url: '*example.com/*' }, []);
|
||||
},
|
||||
|
||||
setStyle(styleProperties: 'geojson' | 'raster' | 'both' | 'layer' | '', zoom? : number) {
|
||||
let url = "?debug";
|
||||
switch (styleProperties) {
|
||||
case "geojson":
|
||||
url += "&style=http://localhost:8888/geojson-style.json";
|
||||
break;
|
||||
case "raster":
|
||||
url += "&style=http://localhost:8888/raster-style.json";
|
||||
break;
|
||||
case "both":
|
||||
url += "&style=http://localhost:8888/geojson-raster-style.json";
|
||||
break;
|
||||
case "layer":
|
||||
url += "&style=http://localhost:8888/example-layer-style.json";
|
||||
break;
|
||||
}
|
||||
if (zoom) {
|
||||
url += "#" + zoom + "/41.3805/2.1635";
|
||||
}
|
||||
cy.visit("http://localhost:8888/" + url);
|
||||
if (styleProperties) {
|
||||
cy.on('window:confirm', () => true)
|
||||
}
|
||||
cy.get(".maputnik-toolbar-link").should("be.visible");
|
||||
},
|
||||
|
||||
getDataAttribute(key: string, selector?: string) {
|
||||
return `*[data-wd-key='${key}'] ${selector || ''}`;
|
||||
},
|
||||
|
||||
closeModal(key: string) {
|
||||
const selector = this.getDataAttribute(key);
|
||||
|
||||
this.isDisplayedInViewport(selector);
|
||||
|
||||
this.click(this.getDataAttribute(key + ".close-modal"));
|
||||
|
||||
this.doesNotExists(selector);
|
||||
},
|
||||
|
||||
openLayersModal() {
|
||||
cy.get(this.getDataAttribute('layer-list:add-layer')).click();
|
||||
|
||||
cy.get(this.getDataAttribute('modal:add-layer')).should('exist');
|
||||
cy.get(this.getDataAttribute('modal:add-layer')).should('be.visible');
|
||||
},
|
||||
|
||||
getStyleFromWindow(win: Window) {
|
||||
const styleId = win.localStorage.getItem("maputnik:latest_style");
|
||||
const styleItem = win.localStorage.getItem(`maputnik:style:${styleId}`)
|
||||
const obj = JSON.parse(styleItem || "");
|
||||
return obj;
|
||||
},
|
||||
|
||||
isStyleStoreEqual(getter: (obj:any) => any, styleObj: any) {
|
||||
cy.window().then((win: any) => {
|
||||
const obj = this.getStyleFromWindow(win);
|
||||
assert.deepEqual(getter(obj), styleObj);
|
||||
});
|
||||
},
|
||||
|
||||
isStyleStoreEqualToExampleFileData() {
|
||||
cy.window().then((win: any) => {
|
||||
const obj = this.getStyleFromWindow(win);
|
||||
cy.fixture('example-style.json').should('deep.equal', obj);
|
||||
});
|
||||
},
|
||||
|
||||
fillLayersModal(opts: any) {
|
||||
var type = opts.type;
|
||||
var layer = opts.layer;
|
||||
var id;
|
||||
if(opts.id) {
|
||||
id = opts.id
|
||||
}
|
||||
else {
|
||||
id = `${type}:${uuid()}`;
|
||||
}
|
||||
|
||||
cy.get(this.getDataAttribute('add-layer.layer-type', "select")).select(type);
|
||||
cy.get(this.getDataAttribute("add-layer.layer-id", "input")).type(id);
|
||||
if(layer) {
|
||||
cy.get(this.getDataAttribute("add-layer.layer-source-block", "input")).type(layer);
|
||||
}
|
||||
cy.get(this.getDataAttribute("add-layer")).click();
|
||||
|
||||
return id;
|
||||
},
|
||||
|
||||
typeKeys(keys: string) {
|
||||
cy.get('body').type(keys);
|
||||
},
|
||||
|
||||
click(selector: string) {
|
||||
cy.get(selector).click();
|
||||
},
|
||||
|
||||
select(selector: string, value: string) {
|
||||
cy.get(selector).select(value);
|
||||
},
|
||||
|
||||
isSelected(selector: string, value: string) {
|
||||
cy.get(selector).find(`option[value="${value}"]`).should("be.selected");
|
||||
},
|
||||
|
||||
|
||||
focus(selector: string) {
|
||||
cy.get(selector).focus();
|
||||
},
|
||||
|
||||
isFocused(selector: string) {
|
||||
cy.get(selector).should('have.focus');
|
||||
},
|
||||
|
||||
isDisplayedInViewport(selector: string) {
|
||||
cy.get(selector).should('be.visible');
|
||||
},
|
||||
|
||||
isNotDisplayedInViewport(selector: string) {
|
||||
cy.get(selector).should('not.be.visible');
|
||||
},
|
||||
|
||||
setValue(selector: string, text: string) {
|
||||
cy.get(selector).clear().type(text, {parseSpecialCharSequences: false});
|
||||
},
|
||||
|
||||
isExists(selector: string) {
|
||||
cy.get(selector).should('exist');
|
||||
},
|
||||
|
||||
doesNotExists(selector: string) {
|
||||
cy.get(selector).should('not.exist');
|
||||
},
|
||||
|
||||
chooseExampleFile() {
|
||||
cy.get("input[type='file']").selectFile('cypress/fixtures/example-style.json', {force: true});
|
||||
},
|
||||
|
||||
getExampleFileUrl() {
|
||||
return "http://localhost:8888/example-style.json";
|
||||
},
|
||||
|
||||
waitForExampleFileRequset() {
|
||||
cy.wait('@example-style.json');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
80
cypress/e2e/history.cy.ts
Normal file
80
cypress/e2e/history.cy.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import driver from "./driver";
|
||||
|
||||
describe("history", () => {
|
||||
let undoKeyCombo: string;
|
||||
let redoKeyCombo: string;
|
||||
|
||||
before(() => {
|
||||
const isMac = driver.isMac();
|
||||
undoKeyCombo = isMac ? '{meta}z' : '{ctrl}z';
|
||||
redoKeyCombo = isMac ? '{meta}{shift}z' : '{ctrl}y';
|
||||
driver.beforeEach();
|
||||
});
|
||||
|
||||
it("undo/redo", () => {
|
||||
driver.setStyle('geojson');
|
||||
driver.openLayersModal();
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, []);
|
||||
|
||||
driver.fillLayersModal({
|
||||
id: "step 1",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
driver.openLayersModal();
|
||||
driver.fillLayersModal({
|
||||
id: "step 2",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
},
|
||||
{
|
||||
"id": "step 2",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
driver.typeKeys(undoKeyCombo);
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
driver.typeKeys(undoKeyCombo)
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, []);
|
||||
|
||||
driver.typeKeys(redoKeyCombo)
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
driver.typeKeys(redoKeyCombo)
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
},
|
||||
{
|
||||
"id": "step 2",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
});
|
||||
})
|
||||
60
cypress/e2e/keyboard.cy.ts
Normal file
60
cypress/e2e/keyboard.cy.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import driver from "./driver";
|
||||
|
||||
describe("keyboard", () => {
|
||||
describe("shortcuts", () => {
|
||||
beforeEach(() => {
|
||||
driver.setupInterception();
|
||||
driver.setStyle('');
|
||||
})
|
||||
|
||||
it("ESC should unfocus", () => {
|
||||
const targetSelector = driver.getDataAttribute("nav:inspect") + " select";
|
||||
driver.focus(targetSelector);
|
||||
driver.isFocused(targetSelector);
|
||||
|
||||
//driver.typeKeys("{esc}");
|
||||
//driver.isFocused('body');
|
||||
});
|
||||
|
||||
it("'?' should show shortcuts modal", () => {
|
||||
driver.typeKeys("?");
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:shortcuts"));
|
||||
});
|
||||
|
||||
it("'o' should show open modal", () => {
|
||||
driver.typeKeys("o");
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:open"));
|
||||
});
|
||||
|
||||
it("'e' should show export modal", () => {
|
||||
driver.typeKeys("e");
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:export"));
|
||||
});
|
||||
|
||||
it("'d' should show sources modal", () => {
|
||||
driver.typeKeys("d");
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:sources"));
|
||||
});
|
||||
|
||||
it("'s' should show settings modal", () => {
|
||||
driver.typeKeys("s");
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:settings"));
|
||||
});
|
||||
|
||||
it("'i' should change map to inspect mode", () => {
|
||||
driver.typeKeys("i");
|
||||
driver.isSelected(driver.getDataAttribute("nav:inspect"), "inspect");
|
||||
});
|
||||
|
||||
it("'m' should focus map", () => {
|
||||
driver.typeKeys("m");
|
||||
driver.isFocused(".maplibregl-canvas");
|
||||
});
|
||||
|
||||
it("'!' should show debug modal", () => {
|
||||
driver.typeKeys("!");
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:debug"));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
427
cypress/e2e/layers.cy.ts
Normal file
427
cypress/e2e/layers.cy.ts
Normal file
@@ -0,0 +1,427 @@
|
||||
var assert = require("assert");
|
||||
import driver from "./driver";
|
||||
import { v1 as uuid } from 'uuid';
|
||||
|
||||
describe("layers", () => {
|
||||
beforeEach(() => {
|
||||
driver.beforeEach();
|
||||
driver.setStyle('both');
|
||||
driver.openLayersModal();
|
||||
});
|
||||
|
||||
describe("ops", () => {
|
||||
it("delete", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
},
|
||||
]);
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:"+id+":delete", ""))
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, []);
|
||||
});
|
||||
|
||||
it("duplicate", () => {
|
||||
var styleObj;
|
||||
var id = driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
},
|
||||
]);
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:"+id+":copy", ""));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id+"-copy",
|
||||
"type": "background"
|
||||
},
|
||||
{
|
||||
"id": id,
|
||||
"type": "background"
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("hide", () => {
|
||||
var styleObj;
|
||||
var id = driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
},
|
||||
]);
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:"+id+":toggle-visibility", ""));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "background",
|
||||
"layout": {
|
||||
"visibility": "none"
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:"+id+":toggle-visibility", ""));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "background",
|
||||
"layout": {
|
||||
"visibility": "visible"
|
||||
}
|
||||
},
|
||||
]);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('background', () => {
|
||||
|
||||
it("add", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
describe("modify", () => {
|
||||
function createBackground() {
|
||||
// Setup
|
||||
var id = uuid();
|
||||
|
||||
driver.select(driver.getDataAttribute("add-layer.layer-type", "select"), "background");
|
||||
driver.setValue(driver.getDataAttribute("add-layer.layer-id", "input"), "background:"+id);
|
||||
|
||||
driver.click(driver.getDataAttribute("add-layer"));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": 'background:'+id,
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
return id;
|
||||
}
|
||||
|
||||
// ====> THESE SHOULD BE FROM THE SPEC
|
||||
describe("layer", () => {
|
||||
it("expand/collapse");
|
||||
it("id", () => {
|
||||
var bgId = createBackground();
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
|
||||
var id = uuid();
|
||||
driver.setValue(driver.getDataAttribute("layer-editor.layer-id", "input"), "foobar:"+id)
|
||||
driver.click(driver.getDataAttribute("min-zoom"));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": 'foobar:'+id,
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("min-zoom", () => {
|
||||
var bgId = createBackground();
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
driver.setValue(driver.getDataAttribute("min-zoom", 'input[type="text"]'), "1");
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-editor.layer-id", "input"));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background',
|
||||
"minzoom": 1
|
||||
}
|
||||
]);
|
||||
|
||||
// AND RESET!
|
||||
// driver.setValue(driver.getDataAttribute("min-zoom", "input"), "")
|
||||
// driver.click(driver.getDataAttribute("max-zoom", "input"));
|
||||
|
||||
// driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
// {
|
||||
// "id": 'background:'+bgId,
|
||||
// "type": 'background'
|
||||
// }
|
||||
// ]);
|
||||
});
|
||||
|
||||
it("max-zoom", () => {
|
||||
var bgId = createBackground();
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
driver.setValue(driver.getDataAttribute("max-zoom", 'input[type="text"]'), "1")
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-editor.layer-id", "input"));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background',
|
||||
"maxzoom": 1
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("comments", () => {
|
||||
var bgId = createBackground();
|
||||
var id = uuid();
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
driver.setValue(driver.getDataAttribute("layer-comment", "textarea"), id);
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-editor.layer-id", "input"));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background',
|
||||
metadata: {
|
||||
'maputnik:comment': id
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
// Unset it again.
|
||||
// TODO: This fails
|
||||
// driver.setValue(driver.getDataAttribute("layer-comment", "textarea"), "");
|
||||
// driver.click(driver.getDataAttribute("min-zoom", "input"));
|
||||
|
||||
// driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
// {
|
||||
// "id": 'background:'+bgId,
|
||||
// "type": 'background'
|
||||
// }
|
||||
// ]);
|
||||
});
|
||||
|
||||
it("color", () => {
|
||||
var bgId = createBackground();
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
|
||||
driver.click(driver.getDataAttribute("spec-field:background-color", "input"));
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
describe("filter", () => {
|
||||
it("expand/collapse");
|
||||
it("compound filter");
|
||||
})
|
||||
|
||||
describe("paint", () => {
|
||||
it("expand/collapse");
|
||||
it("color");
|
||||
it("pattern");
|
||||
it("opacity");
|
||||
})
|
||||
// <=====
|
||||
|
||||
describe("json-editor", () => {
|
||||
it("expand/collapse");
|
||||
it("modify");
|
||||
|
||||
// TODO
|
||||
it.skip("parse error", () => {
|
||||
var bgId = createBackground();
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
|
||||
var errorSelector = ".CodeMirror-lint-marker-error";
|
||||
driver.doesNotExists(errorSelector);
|
||||
|
||||
driver.click(".CodeMirror");
|
||||
driver.typeKeys("\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013 {");
|
||||
driver.isExists(errorSelector);
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-editor.layer-id"));
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('fill', () => {
|
||||
it("add", () => {
|
||||
|
||||
var id = driver.fillLayersModal({
|
||||
type: "fill",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'fill',
|
||||
"source": "example"
|
||||
}
|
||||
]);
|
||||
})
|
||||
|
||||
// TODO: Change source
|
||||
it("change source")
|
||||
});
|
||||
|
||||
describe('line', () => {
|
||||
it("add", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "line",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "line",
|
||||
"source": "example",
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("groups", () => {
|
||||
// TODO
|
||||
// Click each of the layer groups.
|
||||
})
|
||||
});
|
||||
|
||||
describe('symbol', () => {
|
||||
it("add", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "symbol",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "symbol",
|
||||
"source": "example",
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('raster', () => {
|
||||
it("add", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "raster",
|
||||
layer: "raster"
|
||||
});
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "raster",
|
||||
"source": "raster",
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('circle', () => {
|
||||
it("add", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "circle",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "circle",
|
||||
"source": "example",
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('fill extrusion', () => {
|
||||
it("add", () => {
|
||||
var id = driver.fillLayersModal({
|
||||
type: "fill-extrusion",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
driver.isStyleStoreEqual((a: any) => a.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'fill-extrusion',
|
||||
"source": "example"
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("groups", () => {
|
||||
it("simple", () => {
|
||||
driver.setStyle("geojson");
|
||||
|
||||
driver.openLayersModal();
|
||||
driver.fillLayersModal({
|
||||
id: "foo",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.openLayersModal();
|
||||
driver.fillLayersModal({
|
||||
id: "foo_bar",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.openLayersModal();
|
||||
driver.fillLayersModal({
|
||||
id: "foo_bar_baz",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo"));
|
||||
driver.isNotDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar"));
|
||||
driver.isNotDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar_baz"));
|
||||
|
||||
driver.click(driver.getDataAttribute("layer-list-group:foo-0"));
|
||||
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo"));
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar"));
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar_baz"));
|
||||
})
|
||||
})
|
||||
});
|
||||
25
cypress/e2e/map.cy.ts
Normal file
25
cypress/e2e/map.cy.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import driver from "./driver";
|
||||
|
||||
describe("map", () => {
|
||||
describe("zoom level", () => {
|
||||
beforeEach(() => {
|
||||
driver.beforeEach();
|
||||
});
|
||||
it("via url", () => {
|
||||
var zoomLevel = 12.37;
|
||||
driver.setStyle("geojson", zoomLevel);
|
||||
driver.isDisplayedInViewport(".maplibregl-ctrl-zoom");
|
||||
// HM TODO
|
||||
//driver.getText(".maplibregl-ctrl-zoom") === "Zoom "+(zoomLevel);
|
||||
})
|
||||
it("via map controls", () => {
|
||||
var zoomLevel = 12.37;
|
||||
driver.setStyle("geojson", zoomLevel);
|
||||
|
||||
driver.click(".maplibregl-ctrl-zoom-in");
|
||||
driver.isDisplayedInViewport(".maplibregl-ctrl-zoom");
|
||||
// HM TODO
|
||||
//driver.getText(".maplibregl-ctrl-zoom") === "Zoom "+(zoomLevel + 1);
|
||||
})
|
||||
})
|
||||
})
|
||||
137
cypress/e2e/modals.cy.ts
Normal file
137
cypress/e2e/modals.cy.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
import driver from "./driver";
|
||||
|
||||
describe("modals", () => {
|
||||
beforeEach(() => {
|
||||
driver.beforeEach();
|
||||
driver.setStyle('');
|
||||
});
|
||||
describe("open", () => {
|
||||
beforeEach(() => {
|
||||
driver.click(driver.getDataAttribute("nav:open"));
|
||||
});
|
||||
|
||||
it("close", () => {
|
||||
driver.closeModal("modal:open");
|
||||
});
|
||||
|
||||
it.skip("upload", () => {
|
||||
// HM: I was not able to make the following choose file actually to select a file and close the modal...
|
||||
driver.chooseExampleFile();
|
||||
|
||||
driver.isStyleStoreEqualToExampleFileData();
|
||||
});
|
||||
|
||||
it("load from url", () => {
|
||||
var styleFileUrl = driver.getExampleFileUrl();
|
||||
|
||||
driver.setValue(driver.getDataAttribute("modal:open.url.input"), styleFileUrl);
|
||||
driver.click(driver.getDataAttribute("modal:open.url.button"))
|
||||
driver.waitForExampleFileRequset();
|
||||
|
||||
driver.isStyleStoreEqualToExampleFileData();
|
||||
});
|
||||
})
|
||||
|
||||
describe("shortcuts", () => {
|
||||
it("open/close", () => {
|
||||
driver.setStyle('');
|
||||
|
||||
driver.typeKeys("?");
|
||||
|
||||
driver.isDisplayedInViewport(driver.getDataAttribute("modal:shortcuts"));
|
||||
|
||||
driver.closeModal("modal:shortcuts");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("export", () => {
|
||||
beforeEach(() => {
|
||||
driver.click(driver.getDataAttribute("nav:export"));
|
||||
});
|
||||
|
||||
it("close", () => {
|
||||
driver.closeModal("modal:export");
|
||||
});
|
||||
|
||||
// TODO: Work out how to download a file and check the contents
|
||||
it("download")
|
||||
|
||||
})
|
||||
|
||||
describe("sources", () => {
|
||||
it("active sources")
|
||||
it("public source")
|
||||
it("add new source")
|
||||
})
|
||||
|
||||
describe("inspect", () => {
|
||||
it("toggle", () => {
|
||||
driver.setStyle('geojson');
|
||||
|
||||
driver.select(driver.getDataAttribute("nav:inspect", "select"), "inspect");
|
||||
})
|
||||
})
|
||||
|
||||
describe("style settings", () => {
|
||||
beforeEach(() => {
|
||||
driver.click(driver.getDataAttribute("nav:settings"));
|
||||
});
|
||||
|
||||
it("name", () => {
|
||||
driver.setValue(driver.getDataAttribute("modal:settings.name"), "foobar");
|
||||
driver.click(driver.getDataAttribute("modal:settings.owner"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.name, "foobar");
|
||||
})
|
||||
it("owner", () => {
|
||||
driver.setValue(driver.getDataAttribute("modal:settings.owner"), "foobar")
|
||||
driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.owner, "foobar");
|
||||
})
|
||||
it("sprite url", () => {
|
||||
driver.setValue(driver.getDataAttribute("modal:settings.sprite"), "http://example.com")
|
||||
driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.sprite, "http://example.com");
|
||||
})
|
||||
it("glyphs url", () => {
|
||||
var glyphsUrl = "http://example.com/{fontstack}/{range}.pbf"
|
||||
driver.setValue(driver.getDataAttribute("modal:settings.glyphs"), glyphsUrl);
|
||||
driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.glyphs, glyphsUrl);
|
||||
})
|
||||
|
||||
it("maptiler access token", () => {
|
||||
var apiKey = "testing123";
|
||||
driver.setValue(driver.getDataAttribute("modal:settings.maputnik:openmaptiles_access_token"), apiKey);
|
||||
driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.metadata["maputnik:openmaptiles_access_token"], apiKey);
|
||||
})
|
||||
|
||||
it("thunderforest access token", () => {
|
||||
var apiKey = "testing123";
|
||||
driver.setValue(driver.getDataAttribute("modal:settings.maputnik:thunderforest_access_token"), apiKey);
|
||||
driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.metadata["maputnik:thunderforest_access_token"], apiKey);
|
||||
})
|
||||
|
||||
it("style renderer", () => {
|
||||
cy.on('uncaught:exception', () => false); // this is due to the fact that this is an invalid style for openlayers
|
||||
driver.select(driver.getDataAttribute("modal:settings.maputnik:renderer"), "ol");
|
||||
driver.isSelected(driver.getDataAttribute("modal:settings.maputnik:renderer"), "ol");
|
||||
|
||||
driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
|
||||
driver.isStyleStoreEqual((obj) => obj.metadata["maputnik:renderer"], "ol");
|
||||
})
|
||||
})
|
||||
|
||||
describe("sources", () => {
|
||||
it("toggle")
|
||||
})
|
||||
})
|
||||
34
cypress/fixtures/geojson-raster-style.json
Normal file
34
cypress/fixtures/geojson-raster-style.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"id": "test-style",
|
||||
"version": 8,
|
||||
"name": "Test Style",
|
||||
"metadata": {
|
||||
"maputnik:renderer": "mlgljs"
|
||||
},
|
||||
"sources": {
|
||||
"example": {
|
||||
"type": "vector",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features":[{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Dinagat Islands"
|
||||
},
|
||||
"geometry":{
|
||||
"type": "Point",
|
||||
"coordinates": [125.6, 10.1]
|
||||
}
|
||||
}]
|
||||
}
|
||||
},
|
||||
"raster": {
|
||||
"tileSize": 256,
|
||||
"tiles": ["http://localhost/example/{x}/{y}/{z}"],
|
||||
"type": "raster"
|
||||
}
|
||||
},
|
||||
"glyphs": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"layers": []
|
||||
}
|
||||
29
cypress/fixtures/geojson-style.json
Normal file
29
cypress/fixtures/geojson-style.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"id": "test-style",
|
||||
"version": 8,
|
||||
"name": "Test Style",
|
||||
"metadata": {
|
||||
"maputnik:renderer": "mlgljs"
|
||||
},
|
||||
"sources": {
|
||||
"example": {
|
||||
"type": "vector",
|
||||
"data": {
|
||||
"type": "FeatureCollection",
|
||||
"features":[{
|
||||
"type": "Feature",
|
||||
"properties": {
|
||||
"name": "Dinagat Islands"
|
||||
},
|
||||
"geometry":{
|
||||
"type": "Point",
|
||||
"coordinates": [125.6, 10.1]
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"glyphs": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"layers": []
|
||||
}
|
||||
18
cypress/fixtures/raster-style.json
Normal file
18
cypress/fixtures/raster-style.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "test-style",
|
||||
"version": 8,
|
||||
"name": "Test Style",
|
||||
"metadata": {
|
||||
"maputnik:renderer": "mlgljs"
|
||||
},
|
||||
"sources": {
|
||||
"raster": {
|
||||
"tileSize": 256,
|
||||
"tiles": ["http://localhost/example/{x}/{y}/{z}"],
|
||||
"type": "raster"
|
||||
}
|
||||
},
|
||||
"glyphs": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"sprites": "https://example.local/fonts/{fontstack}/{range}.pbf",
|
||||
"layers": []
|
||||
}
|
||||
37
cypress/support/commands.ts
Normal file
37
cypress/support/commands.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/// <reference types="cypress" />
|
||||
// ***********************************************
|
||||
// This example commands.ts shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
20
cypress/support/e2e.ts
Normal file
20
cypress/support/e2e.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.ts is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
8323
package-lock.json
generated
8323
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
15
package.json
15
package.json
@@ -7,8 +7,8 @@
|
||||
"stats": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack --config config/webpack.production.config.js --progress=profile --json > stats.json",
|
||||
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack --config config/webpack.production.config.js --progress=profile --color",
|
||||
"profiling-build": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack --config config/webpack.profiling.config.js --progress=profile --color",
|
||||
"test": "cross-env NODE_OPTIONS=--openssl-legacy-provider cross-env NODE_ENV=test wdio config/wdio.conf.js",
|
||||
"test-watch": "cross-env NODE_OPTIONS=--openssl-legacy-provider cross-env NODE_ENV=test wdio config/wdio.conf.js --watch",
|
||||
"test": "cypress run",
|
||||
"cy:open": "cypress open",
|
||||
"start": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack-dev-server --progress=profile --color --config config/webpack.config.js",
|
||||
"start-prod": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack-dev-server --progress=profile --color --config config/webpack.production.config.js",
|
||||
"start-sandbox": "cross-env NODE_OPTIONS=--openssl-legacy-provider webpack-dev-server --disable-host-check --host 0.0.0.0 --progress=profile --color --config config/webpack.production.config.js",
|
||||
@@ -133,11 +133,8 @@
|
||||
"@storybook/addons": "^6.4.20",
|
||||
"@storybook/react": "^6.4.20",
|
||||
"@storybook/theming": "^6.4.20",
|
||||
"@wdio/cli": "^7.19.3",
|
||||
"@wdio/local-runner": "^7.19.3",
|
||||
"@wdio/mocha-framework": "^7.19.3",
|
||||
"@wdio/selenium-standalone-service": "^7.19.1",
|
||||
"@wdio/spec-reporter": "^7.19.1",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/uuid": "^9.0.7",
|
||||
"babel-loader": "^8.2.4",
|
||||
"babel-plugin-istanbul": "^6.1.1",
|
||||
"babel-plugin-static-fs": "^3.0.0",
|
||||
@@ -145,6 +142,7 @@
|
||||
"cors": "^2.8.5",
|
||||
"cross-env": "^7.0.3",
|
||||
"css-loader": "^5.2.7",
|
||||
"cypress": "^13.6.1",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-react": "^7.29.4",
|
||||
"express": "^4.17.3",
|
||||
@@ -163,9 +161,8 @@
|
||||
"stylelint-scss": "^4.2.0",
|
||||
"svg-inline-loader": "^0.8.2",
|
||||
"transform-loader": "^0.2.4",
|
||||
"typescript": "^4.6.3",
|
||||
"typescript": "^4.9.5",
|
||||
"uuid": "^8.3.2",
|
||||
"webdriverio": "^7.19.3",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-cleanup-plugin": "^0.5.1",
|
||||
|
||||
@@ -18,13 +18,6 @@
|
||||
@import 'codemirror';
|
||||
@import 'react-collapse';
|
||||
|
||||
/**
|
||||
* Hacks for webdriverio isVisibleWithinViewport
|
||||
*/
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.maputnik-layout {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
|
||||
const testNetwork = process.env.TEST_NETWORK || "localhost";
|
||||
const port = 9001;
|
||||
const baseUrl = `http://${testNetwork}:${port}`;
|
||||
const config = {
|
||||
testNetwork,
|
||||
port,
|
||||
baseUrl
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
@@ -1,43 +0,0 @@
|
||||
var assert = require("assert");
|
||||
var driver = require("../driver");
|
||||
|
||||
describe("accessibility", function () {
|
||||
describe("skip links", function() {
|
||||
beforeEach(async function () {
|
||||
await driver.setStyle("example-layer-style.json");
|
||||
});
|
||||
|
||||
it("skip link to layer list", async function() {
|
||||
const selector = driver.getDataAttribute("root:skip:layer-list")
|
||||
assert(await driver.isExisting(selector));
|
||||
await driver.typeKeys(['Tab']);
|
||||
assert(await driver.isFocused(selector));
|
||||
await driver.click(selector);
|
||||
|
||||
assert(await driver.isFocused("#skip-target-layer-list"));
|
||||
});
|
||||
|
||||
it("skip link to layer editor", async function() {
|
||||
const selector = driver.getDataAttribute("root:skip:layer-editor")
|
||||
assert(await driver.isExisting(selector));
|
||||
await driver.typeKeys(['Tab']);
|
||||
await driver.typeKeys(['Tab']);
|
||||
assert(await driver.isFocused(selector));
|
||||
await driver.click(selector);
|
||||
|
||||
assert(await driver.isFocused("#skip-target-layer-editor"));
|
||||
});
|
||||
|
||||
it("skip link to map view", async function() {
|
||||
const selector = driver.getDataAttribute("root:skip:map-view")
|
||||
assert(await driver.isExisting(selector));
|
||||
await driver.typeKeys(['Tab']);
|
||||
await driver.typeKeys(['Tab']);
|
||||
await driver.typeKeys(['Tab']);
|
||||
assert(await driver.isFocused(selector));
|
||||
await driver.click(selector);
|
||||
|
||||
assert(await driver.isFocused(".maplibregl-canvas"));
|
||||
});
|
||||
});
|
||||
})
|
||||
@@ -1,218 +0,0 @@
|
||||
var {v1: uuid} = require('uuid');
|
||||
var fs = require("fs");
|
||||
var path = require("path");
|
||||
var config = require("../config/specs");
|
||||
var geoServer = require("../geojson-server");
|
||||
var artifacts = require("../artifacts");
|
||||
|
||||
var SCREENSHOTS_PATH = artifacts.pathSync("/screenshots");
|
||||
|
||||
var testNetwork = process.env.TEST_NETWORK || "localhost";
|
||||
var geoserver;
|
||||
|
||||
|
||||
const driver = {
|
||||
geoserver: {
|
||||
start(done) {
|
||||
geoserver = geoServer.listen(9002, "0.0.0.0", done);
|
||||
},
|
||||
stop(done) {
|
||||
geoserver.close(done);
|
||||
geoserver = undefined;
|
||||
},
|
||||
},
|
||||
getStyleUrl(styles) {
|
||||
var port = geoserver.address().port;
|
||||
return "http://"+testNetwork+":"+port+"/styles/empty/"+styles.join(",");
|
||||
},
|
||||
getGeoServerUrl(urlPath) {
|
||||
var port = geoserver.address().port;
|
||||
return "http://"+testNetwork+":"+port+"/"+urlPath;
|
||||
},
|
||||
|
||||
async setStyle(styleProperties, zoom) {
|
||||
let url = config.baseUrl + "?debug";
|
||||
if (styleProperties && Array.isArray(styleProperties)) {
|
||||
url += "&style=" + this.getStyleUrl(styleProperties);
|
||||
} else if (styleProperties && typeof styleProperties === "string") {
|
||||
url += "&style=" + this.getGeoServerUrl(styleProperties);
|
||||
}
|
||||
if (zoom) {
|
||||
url += "#" + zoom + "/41.3805/2.1635";
|
||||
}
|
||||
await browser.url(url);
|
||||
if (styleProperties) {
|
||||
await browser.acceptAlert();
|
||||
}
|
||||
await this.waitForExist(".maputnik-toolbar-link");
|
||||
await this.zeroTimeout();
|
||||
},
|
||||
async getStyleStore() {
|
||||
return await browser.executeAsync(function(done) {
|
||||
window.debug.get("maputnik", "styleStore").latestStyle(done);
|
||||
});
|
||||
},
|
||||
async setSurvey() {
|
||||
await browser.execute(function() {
|
||||
localStorage.setItem("survey", true);
|
||||
});
|
||||
},
|
||||
async isMac() {
|
||||
return await browser.execute(function() {
|
||||
return navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||
});
|
||||
},
|
||||
async typeKeys(keys) {
|
||||
await browser.keys(keys)
|
||||
},
|
||||
async click(selector) {
|
||||
const elem = await $(selector);
|
||||
await elem.click();
|
||||
},
|
||||
async selectFromDropdown(selector, value) {
|
||||
const selectBox = await $(selector);
|
||||
await selectBox.selectByAttribute('value', value);
|
||||
await this.zeroTimeout();
|
||||
},
|
||||
async isDisplayedInViewport(selector) {
|
||||
const elem = await $(selector);
|
||||
return elem.isDisplayedInViewport();
|
||||
},
|
||||
async isFocused(selector) {
|
||||
const elem = await $(selector);
|
||||
return elem.isFocused();
|
||||
},
|
||||
/**
|
||||
* Sometimes chrome driver can result in the wrong text.
|
||||
*
|
||||
* See <https://github.com/webdriverio/webdriverio/issues/1886>
|
||||
*/
|
||||
async setValue(selector, text) {
|
||||
for (var i = 0; i < 10; i++) {
|
||||
const elem = await $(selector);
|
||||
await elem.waitForDisplayed(500);
|
||||
|
||||
var elements = await browser.findElements("css selector", selector);
|
||||
if (elements.length > 1) {
|
||||
throw "Too many elements found";
|
||||
}
|
||||
|
||||
const elem2 = await $(selector);
|
||||
await elem2.setValue(text);
|
||||
|
||||
var browserText = await elem2.getValue();
|
||||
|
||||
if (browserText == text) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
console.error("Warning: setValue failed, trying again");
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for change events to fire and state updated
|
||||
await this.zeroTimeout();
|
||||
},
|
||||
getExampleFilePath() {
|
||||
return __dirname + "/../example-style.json";
|
||||
},
|
||||
async getExampleFileData() {
|
||||
var styleFilePath = this.getExampleFilePath();
|
||||
return JSON.parse(fs.readFileSync(styleFilePath));
|
||||
},
|
||||
async chooseExampleFile() {
|
||||
const elem = await $("*[type='file']");
|
||||
await elem.waitForExist();
|
||||
await browser.chooseFile("*[type='file']", this.getExampleFilePath());
|
||||
},
|
||||
async zeroTimeout() {
|
||||
await browser.executeAsync(function (done) {
|
||||
// For any events to propagate
|
||||
setTimeout(function () {
|
||||
// For the DOM to be updated.
|
||||
setTimeout(done, 0);
|
||||
}, 0)
|
||||
})
|
||||
},
|
||||
async sleep(milliseconds) {
|
||||
await browser.pause(milliseconds);
|
||||
},
|
||||
async isExisting(selector) {
|
||||
const elem = await $(selector);
|
||||
return elem.isExisting();
|
||||
},
|
||||
async waitForExist(selector) {
|
||||
const elem = await $(selector);
|
||||
await elem.waitForExist();
|
||||
},
|
||||
async setWindowSize(height, width) {
|
||||
await browser.setWindowSize(height, width);
|
||||
},
|
||||
async takeScreenShot(filepath) {
|
||||
var savepath = path.join(SCREENSHOTS_PATH, filepath);
|
||||
await browser.saveScreenshot(savepath);
|
||||
},
|
||||
getDataAttribute(key, selector) {
|
||||
selector = selector || "";
|
||||
return "*[data-wd-key='"+key+"'] "+selector;
|
||||
},
|
||||
async openLayersModal() {
|
||||
const selector = await $(this.getDataAttribute('layer-list:add-layer'));
|
||||
await selector.click();
|
||||
|
||||
// Wait for events
|
||||
await this.zeroTimeout();
|
||||
|
||||
const elem = await $(this.getDataAttribute('modal:add-layer'));
|
||||
await elem.waitForExist();
|
||||
await elem.isDisplayed();
|
||||
await elem.isDisplayedInViewport();
|
||||
|
||||
// Wait for events
|
||||
await this.zeroTimeout();
|
||||
},
|
||||
async fillLayersModal(opts) {
|
||||
var type = opts.type;
|
||||
var layer = opts.layer;
|
||||
var id;
|
||||
if(opts.id) {
|
||||
id = opts.id
|
||||
}
|
||||
else {
|
||||
id = type+":"+uuid();
|
||||
}
|
||||
|
||||
const selectBox = await $(this.getDataAttribute("add-layer.layer-type", "select"));
|
||||
await selectBox.selectByAttribute('value', type);
|
||||
await this.zeroTimeout();
|
||||
|
||||
await this.setValue(this.getDataAttribute("add-layer.layer-id", "input"), id);
|
||||
if(layer) {
|
||||
await this.setValue(this.getDataAttribute("add-layer.layer-source-block", "input"), layer);
|
||||
}
|
||||
|
||||
await this.zeroTimeout();
|
||||
const elem_addLayer = await $(this.getDataAttribute("add-layer"));
|
||||
await elem_addLayer.click();
|
||||
|
||||
return id;
|
||||
},
|
||||
|
||||
async closeModal(wdKey) {
|
||||
const selector = this.getDataAttribute(wdKey);
|
||||
|
||||
await browser.waitUntil(async function() {
|
||||
const elem = await $(selector);
|
||||
return await elem.isDisplayedInViewport();
|
||||
});
|
||||
|
||||
await this.click(this.getDataAttribute(wdKey+".close-modal"));
|
||||
|
||||
await browser.waitUntil(async function() {
|
||||
return await browser.execute((selector) => {
|
||||
return !document.querySelector(selector);
|
||||
}, selector);
|
||||
});
|
||||
}
|
||||
}
|
||||
module.exports = driver;
|
||||
@@ -1,103 +0,0 @@
|
||||
var assert = require("assert");
|
||||
var driver = require("../driver");
|
||||
|
||||
describe("history", function() {
|
||||
let undoKeyCombo;
|
||||
let undoKeyComboReset;
|
||||
let redoKeyCombo;
|
||||
let redoKeyComboReset;
|
||||
|
||||
before(async function() {
|
||||
const isMac = await driver.isMac();
|
||||
undoKeyCombo = ['Meta', 'z'];
|
||||
undoKeyComboReset = ['Meta'];
|
||||
redoKeyCombo = isMac ? ['Meta', 'Shift', 'z'] : ['Meta', 'y'];
|
||||
redoKeyComboReset = isMac ? ['Meta', 'Shift'] : ['Meta'];
|
||||
});
|
||||
|
||||
/**
|
||||
* See <https://github.com/webdriverio/webdriverio/issues/1126>
|
||||
*/
|
||||
it.skip("undo/redo", async function() {
|
||||
var styleObj;
|
||||
|
||||
await driver.setStyle(["geojson:example"])
|
||||
await driver.openLayersModal();
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, []);
|
||||
|
||||
await driver.fillLayersModal({
|
||||
id: "step 1",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
await driver.openLayersModal();
|
||||
await driver.fillLayersModal({
|
||||
id: "step 2",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
},
|
||||
{
|
||||
"id": "step 2",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
await driver.typeKeys(undoKeyCombo);
|
||||
await driver.typeKeys(undoKeyComboReset);
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
await driver.typeKeys(undoKeyCombo)
|
||||
await driver.typeKeys(undoKeyComboReset);
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
]);
|
||||
|
||||
await driver.typeKeys(redoKeyCombo)
|
||||
await driver.typeKeys(redoKeyComboReset);
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
await driver.typeKeys(redoKeyCombo)
|
||||
await driver.typeKeys(redoKeyComboReset);
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": "step 1",
|
||||
"type": 'background'
|
||||
},
|
||||
{
|
||||
"id": "step 2",
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
@@ -1,35 +0,0 @@
|
||||
var driver = require("./driver");
|
||||
|
||||
describe('maputnik', function() {
|
||||
|
||||
before(async function(done) {
|
||||
await browser.setTimeout({ 'script': 20 * 1000 });
|
||||
await browser.setTimeout({ 'implicit': 20 * 1000 });
|
||||
driver.geoserver.start(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
driver.geoserver.stop(done);
|
||||
});
|
||||
|
||||
beforeEach(async function() {
|
||||
await driver.setStyle(["geojson:example","raster:raster"]);
|
||||
await driver.setSurvey();
|
||||
});
|
||||
|
||||
// -------- setup --------
|
||||
require("./util/coverage");
|
||||
// -----------------------
|
||||
|
||||
// ---- All the tests ----
|
||||
require("./history");
|
||||
require("./layers");
|
||||
require("./map");
|
||||
require("./modals");
|
||||
require("./screenshots");
|
||||
require("./accessibility");
|
||||
require("./keyboard");
|
||||
// ------------------------
|
||||
|
||||
});
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
var assert = require("assert");
|
||||
var driver = require("../driver");
|
||||
|
||||
describe("keyboard", function() {
|
||||
describe("shortcuts", function() {
|
||||
it("ESC should unfocus", async function() {
|
||||
const targetSelector = driver.getDataAttribute("nav:inspect") + " select";
|
||||
driver.click(targetSelector);
|
||||
assert(await driver.isFocused(targetSelector));
|
||||
|
||||
await driver.typeKeys(["Escape"]);
|
||||
assert(await (await $("body")).isFocused());
|
||||
});
|
||||
|
||||
it("'?' should show shortcuts modal", async function() {
|
||||
await driver.typeKeys(["?"]);
|
||||
assert(await driver.isDisplayedInViewport(driver.getDataAttribute("modal:shortcuts")));
|
||||
});
|
||||
|
||||
it("'o' should show open modal", async function() {
|
||||
await driver.typeKeys(["o"]);
|
||||
assert(await driver.isDisplayedInViewport(driver.getDataAttribute("modal:open")));
|
||||
});
|
||||
|
||||
it("'e' should show export modal", async function() {
|
||||
await driver.typeKeys(["e"]);
|
||||
await driver.sleep(100);
|
||||
assert(await driver.isDisplayedInViewport(driver.getDataAttribute("modal:export")));
|
||||
});
|
||||
|
||||
it("'d' should show sources modal", async function() {
|
||||
await driver.typeKeys(["d"]);
|
||||
assert(await driver.isDisplayedInViewport(driver.getDataAttribute("modal:sources")));
|
||||
});
|
||||
|
||||
it("'s' should show settings modal", async function() {
|
||||
await driver.typeKeys(["s"]);
|
||||
assert(await driver.isDisplayedInViewport(driver.getDataAttribute("modal:settings")));
|
||||
});
|
||||
|
||||
it.skip("'i' should change map to inspect mode", async function() {
|
||||
// await driver.typeKeys(["i"]);
|
||||
});
|
||||
|
||||
it("'m' should focus map", async function() {
|
||||
await driver.typeKeys(["m"]);
|
||||
assert(await driver.isFocused(".maplibregl-canvas"));
|
||||
});
|
||||
|
||||
it("'!' should show debug modal", async function() {
|
||||
await driver.typeKeys(["!"]);
|
||||
assert(await driver.isDisplayedInViewport(driver.getDataAttribute("modal:debug")));
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,458 +0,0 @@
|
||||
var assert = require("assert");
|
||||
var driver = require("../driver");
|
||||
var {v1: uuid} = require('uuid');
|
||||
|
||||
describe("layers", function() {
|
||||
beforeEach(async function() {
|
||||
driver.setStyle([
|
||||
"geojson:example",
|
||||
"raster:raster"
|
||||
]);
|
||||
await driver.openLayersModal();
|
||||
});
|
||||
|
||||
describe("ops", function() {
|
||||
it("delete", async function() {
|
||||
var styleObj;
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
},
|
||||
]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:"+id+":delete", ""))
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
]);
|
||||
});
|
||||
|
||||
it("duplicate", async function() {
|
||||
var styleObj;
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
},
|
||||
]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:"+id+":copy", ""));
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id+"-copy",
|
||||
"type": "background"
|
||||
},
|
||||
{
|
||||
"id": id,
|
||||
"type": "background"
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("hide", async function() {
|
||||
var styleObj;
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
},
|
||||
]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:"+id+":toggle-visibility", ""));
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "background",
|
||||
"layout": {
|
||||
"visibility": "none"
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:"+id+":toggle-visibility", ""));
|
||||
|
||||
styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "background",
|
||||
"layout": {
|
||||
"visibility": "visible"
|
||||
}
|
||||
},
|
||||
]);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('background', function () {
|
||||
|
||||
it("add", async function() {
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "background"
|
||||
})
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
describe("modify", function() {
|
||||
async function createBackground() {
|
||||
// Setup
|
||||
var id = uuid();
|
||||
|
||||
await driver.selectFromDropdown(driver.getDataAttribute("add-layer.layer-type", "select"), "background");
|
||||
await driver.setValue(driver.getDataAttribute("add-layer.layer-id", "input"), "background:"+id);
|
||||
|
||||
await driver.click(driver.getDataAttribute("add-layer"));
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
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", async function() {
|
||||
var bgId = await createBackground();
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
|
||||
var id = uuid();
|
||||
await driver.setValue(driver.getDataAttribute("layer-editor.layer-id", "input"), "foobar:"+id)
|
||||
await driver.click(driver.getDataAttribute("min-zoom"));
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": 'foobar:'+id,
|
||||
"type": 'background'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("min-zoom", async function() {
|
||||
var bgId = await createBackground();
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
await driver.setValue(driver.getDataAttribute("min-zoom", 'input[type="text"]'), 1)
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-editor.layer-id", "input"));
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background',
|
||||
"minzoom": 1
|
||||
}
|
||||
]);
|
||||
|
||||
// AND RESET!
|
||||
// await driver.setValue(driver.getDataAttribute("min-zoom", "input"), "")
|
||||
// await driver.click(driver.getDataAttribute("max-zoom", "input"));
|
||||
|
||||
// var styleObj = await driver.getStyleStore();
|
||||
|
||||
// assert.deepEqual(styleObj.layers, [
|
||||
// {
|
||||
// "id": 'background:'+bgId,
|
||||
// "type": 'background'
|
||||
// }
|
||||
// ]);
|
||||
});
|
||||
|
||||
it("max-zoom", async function() {
|
||||
var bgId = await createBackground();
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
await driver.setValue(driver.getDataAttribute("max-zoom", 'input[type="text"]'), 1)
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-editor.layer-id", "input"));
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background',
|
||||
"maxzoom": 1
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it("comments", async function() {
|
||||
var bgId = await createBackground();
|
||||
var id = uuid();
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
await driver.setValue(driver.getDataAttribute("layer-comment", "textarea"), id);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-editor.layer-id", "input"));
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": 'background:'+bgId,
|
||||
"type": 'background',
|
||||
metadata: {
|
||||
'maputnik:comment': id
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
// Unset it again.
|
||||
// TODO: This fails
|
||||
// await driver.setValue(driver.getDataAttribute("layer-comment", "textarea"), "");
|
||||
// await driver.click(driver.getDataAttribute("min-zoom", "input"));
|
||||
// await driver.zeroTimeout();
|
||||
|
||||
// var styleObj = await driver.getStyleStore();
|
||||
// assert.deepEqual(styleObj.layers, [
|
||||
// {
|
||||
// "id": 'background:'+bgId,
|
||||
// "type": 'background'
|
||||
// }
|
||||
// ]);
|
||||
});
|
||||
|
||||
it("color", null, async function() {
|
||||
var bgId = await createBackground();
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
|
||||
await driver.click(driver.getDataAttribute("spec-field:background-color", "input"));
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
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", async function() {
|
||||
var bgId = await createBackground();
|
||||
|
||||
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-item:background:"+bgId));
|
||||
|
||||
var errorSelector = ".CodeMirror-lint-marker-error";
|
||||
assert.equal(await driver.isExisting(errorSelector), false);
|
||||
|
||||
await driver.click(".CodeMirror");
|
||||
await driver.keys("\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013\uE013 {");
|
||||
await driver.waitForExist(errorSelector);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-editor.layer-id"));
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
describe('fill', function () {
|
||||
it("add", async function() {
|
||||
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "fill",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'fill',
|
||||
"source": "example"
|
||||
}
|
||||
]);
|
||||
})
|
||||
|
||||
// TODO: Change source
|
||||
it("change source")
|
||||
});
|
||||
|
||||
describe('line', function () {
|
||||
it("add", async function() {
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "line",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
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("add", async function() {
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "symbol",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "symbol",
|
||||
"source": "example",
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('raster', function () {
|
||||
it("add", async function() {
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "raster",
|
||||
layer: "raster"
|
||||
});
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "raster",
|
||||
"source": "raster",
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('circle', function () {
|
||||
it("add", async function() {
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "circle",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": "circle",
|
||||
"source": "example",
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('fill extrusion', function () {
|
||||
it("add", async function() {
|
||||
var id = await driver.fillLayersModal({
|
||||
type: "fill-extrusion",
|
||||
layer: "example"
|
||||
});
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(styleObj.layers, [
|
||||
{
|
||||
"id": id,
|
||||
"type": 'fill-extrusion',
|
||||
"source": "example"
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("groups", function() {
|
||||
it("simple", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.openLayersModal();
|
||||
await driver.fillLayersModal({
|
||||
id: "foo",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
await driver.openLayersModal();
|
||||
await driver.fillLayersModal({
|
||||
id: "foo_bar",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
await driver.openLayersModal();
|
||||
await driver.fillLayersModal({
|
||||
id: "foo_bar_baz",
|
||||
type: "background"
|
||||
})
|
||||
|
||||
assert.equal(await driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo")), true);
|
||||
assert.equal(await driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar")), false);
|
||||
assert.equal(await driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar_baz")), false);
|
||||
|
||||
await driver.click(driver.getDataAttribute("layer-list-group:foo-0"));
|
||||
|
||||
assert.equal(await driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo")), true);
|
||||
assert.equal(await driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar")), true);
|
||||
assert.equal(await driver.isDisplayedInViewport(driver.getDataAttribute("layer-list-item:foo_bar_baz")), true);
|
||||
|
||||
})
|
||||
})
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
var driver = require("../driver");
|
||||
|
||||
describe("map", function() {
|
||||
describe.skip("zoom level", function() {
|
||||
it("via url", async function() {
|
||||
var zoomLevel = "12.37";
|
||||
await driver.setStyle(["geojson:example"], zoomLevel);
|
||||
await browser.waitUntil(async function () {
|
||||
return (
|
||||
await browser.isVisible(".maplibregl-ctrl-zoom")
|
||||
&& await browser.getText(".maplibregl-ctrl-zoom") === "Zoom level: "+(zoomLevel)
|
||||
);
|
||||
}, 10*1000)
|
||||
})
|
||||
it("via map controls", async function() {
|
||||
var zoomLevel = 12.37;
|
||||
await driver.setStyle(["geojson:example"], zoomLevel);
|
||||
|
||||
await driver.click(".maplibregl-ctrl-zoom-in");
|
||||
await browser.waitUntil(async function () {
|
||||
var text = await browser.getText(".maplibregl-ctrl-zoom")
|
||||
return text === "Zoom level: "+(zoomLevel+1);
|
||||
}, 10*1000)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,160 +0,0 @@
|
||||
var assert = require('assert');
|
||||
var driver = require("../driver");
|
||||
|
||||
describe("modals", function() {
|
||||
describe("open", function() {
|
||||
beforeEach(async function() {
|
||||
|
||||
await driver.setStyle();
|
||||
await driver.click(driver.getDataAttribute("nav:open"));
|
||||
await driver.zeroTimeout();
|
||||
});
|
||||
|
||||
it("close", async function() {
|
||||
await driver.closeModal("modal:open");
|
||||
});
|
||||
|
||||
// "chooseFile" command currently not available for wdio v5 https://github.com/webdriverio/webdriverio/pull/3632
|
||||
it.skip("upload", async function() {
|
||||
await driver.chooseExampleFile();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(await driver.getExampleFileData(), styleObj);
|
||||
});
|
||||
|
||||
it("load from url", async function() {
|
||||
var styleFileUrl = driver.getGeoServerUrl("example-style.json");
|
||||
|
||||
await driver.setValue(driver.getDataAttribute("modal:open.url.input"), styleFileUrl);
|
||||
|
||||
await driver.click(driver.getDataAttribute("modal:open.url.button"))
|
||||
|
||||
// Allow the network request to happen
|
||||
// NOTE: Its localhost so this should be fast.
|
||||
await driver.sleep(300);
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.deepEqual(await driver.getExampleFileData(), styleObj);
|
||||
});
|
||||
})
|
||||
|
||||
describe("shortcuts", function() {
|
||||
it("open/close", async function() {
|
||||
await driver.setStyle();
|
||||
|
||||
await driver.typeKeys(["?"]);
|
||||
|
||||
const modalEl = await $(driver.getDataAttribute("modal:shortcuts"))
|
||||
assert(await modalEl.isDisplayed());
|
||||
|
||||
await driver.closeModal("modal:shortcuts");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("export", function() {
|
||||
|
||||
beforeEach(async function() {
|
||||
await driver.setStyle();
|
||||
await driver.click(driver.getDataAttribute("nav:export"));
|
||||
await driver.zeroTimeout();
|
||||
});
|
||||
|
||||
it("close", async function() {
|
||||
await driver.closeModal("modal:export");
|
||||
});
|
||||
|
||||
// TODO: Work out how to download a file and check the contents
|
||||
it("download")
|
||||
|
||||
})
|
||||
|
||||
describe("sources", function() {
|
||||
it("active sources")
|
||||
it("public source")
|
||||
it("add new source")
|
||||
})
|
||||
|
||||
describe("inspect", function() {
|
||||
it("toggle", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.selectFromDropdown(driver.getDataAttribute("nav:inspect", "select"), "inspect");
|
||||
})
|
||||
})
|
||||
|
||||
describe("style settings", function() {
|
||||
beforeEach(async function() {
|
||||
await driver.setStyle();
|
||||
await driver.click(driver.getDataAttribute("nav:settings"));
|
||||
await driver.zeroTimeout();
|
||||
});
|
||||
|
||||
it("name", async function() {
|
||||
await driver.setValue(driver.getDataAttribute("modal:settings.name"), "foobar");
|
||||
await driver.click(driver.getDataAttribute("modal:settings.owner"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.name, "foobar");
|
||||
})
|
||||
it("owner", async function() {
|
||||
await driver.setValue(driver.getDataAttribute("modal:settings.owner"), "foobar")
|
||||
await driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.owner, "foobar");
|
||||
})
|
||||
it("sprite url", async function() {
|
||||
await driver.setValue(driver.getDataAttribute("modal:settings.sprite"), "http://example.com")
|
||||
await driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.sprite, "http://example.com");
|
||||
})
|
||||
it("glyphs url", async function() {
|
||||
var glyphsUrl = "http://example.com/{fontstack}/{range}.pbf"
|
||||
await driver.setValue(driver.getDataAttribute("modal:settings.glyphs"), glyphsUrl);
|
||||
await driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.glyphs, glyphsUrl);
|
||||
})
|
||||
|
||||
it("maptiler access token", async function() {
|
||||
var apiKey = "testing123";
|
||||
await driver.setValue(driver.getDataAttribute("modal:settings.maputnik:openmaptiles_access_token"), apiKey);
|
||||
await driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.metadata["maputnik:openmaptiles_access_token"], apiKey);
|
||||
})
|
||||
|
||||
it("thunderforest access token", async function() {
|
||||
var apiKey = "testing123";
|
||||
await driver.setValue(driver.getDataAttribute("modal:settings.maputnik:thunderforest_access_token"), apiKey);
|
||||
await driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.metadata["maputnik:thunderforest_access_token"], apiKey);
|
||||
})
|
||||
|
||||
it("style renderer", async function() {
|
||||
await driver.selectFromDropdown(driver.getDataAttribute("modal:settings.maputnik:renderer"), "ol");
|
||||
await driver.click(driver.getDataAttribute("modal:settings.name"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
var styleObj = await driver.getStyleStore();
|
||||
assert.equal(styleObj.metadata["maputnik:renderer"], "ol");
|
||||
})
|
||||
})
|
||||
|
||||
describe("sources", function() {
|
||||
it("toggle")
|
||||
})
|
||||
})
|
||||
@@ -1,62 +0,0 @@
|
||||
var driver = require("../driver");
|
||||
|
||||
|
||||
// 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(async function() {
|
||||
await driver.setWindowSize(1280, 800)
|
||||
})
|
||||
|
||||
it("front_page", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.takeScreenShot("/front_page.png")
|
||||
})
|
||||
|
||||
it("open", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
await driver.click(driver.getDataAttribute("nav:open"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
await driver.takeScreenShot("/open.png")
|
||||
})
|
||||
|
||||
it("export", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("nav:export"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
await driver.takeScreenShot("/export.png")
|
||||
})
|
||||
|
||||
it("sources", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("nav:sources"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
await driver.takeScreenShot("/sources.png")
|
||||
})
|
||||
|
||||
it("style settings", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.click(driver.getDataAttribute("nav:settings"));
|
||||
await driver.zeroTimeout();
|
||||
|
||||
await driver.takeScreenShot("/settings.png")
|
||||
})
|
||||
|
||||
it("inspect", async function() {
|
||||
await driver.setStyle(["geojson:example"]);
|
||||
|
||||
await driver.selectFromDropdown(driver.getDataAttribute("nav:inspect", "select"), 'inspect');
|
||||
await driver.zeroTimeout();
|
||||
|
||||
await driver.takeScreenShot("/inspect.png")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
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(async function() {
|
||||
// Code coverage
|
||||
var results = await browser.execute(function() {
|
||||
return window.__coverage__;
|
||||
});
|
||||
|
||||
if (results) {
|
||||
coverage.merge(results);
|
||||
}
|
||||
})
|
||||
|
||||
// Dump the coverage to a file
|
||||
after(function() {
|
||||
|
||||
// Sometimes istanbul copies same location entry with null values
|
||||
// crashing the final coverage step. This is just a workaround for now,
|
||||
// since istanbul will be replaced by nyc.
|
||||
const coverageJson = JSON.stringify(coverage, null, 2);
|
||||
let newCoverage = JSON.parse(coverageJson);
|
||||
|
||||
Object.values(newCoverage).forEach(fileCov => {
|
||||
if (fileCov.branchMap) {
|
||||
Object.values(fileCov.branchMap).forEach(branchMapEntry => {
|
||||
let prevLocation = {};
|
||||
branchMapEntry.locations.forEach(curLocation => {
|
||||
if (curLocation.start && curLocation.end &&
|
||||
curLocation.start.column && curLocation.start.line &&
|
||||
curLocation.end.column && curLocation.end.line)
|
||||
{
|
||||
prevLocation = curLocation;
|
||||
}
|
||||
else
|
||||
{
|
||||
curLocation.start.column = prevLocation.start.column;
|
||||
curLocation.start.line = prevLocation.start.line;
|
||||
curLocation.end.column = prevLocation.end.column;
|
||||
curLocation.end.line = prevLocation.end.line;
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const newCoverageJson = JSON.stringify(newCoverage, null, 2);
|
||||
fs.writeFileSync(COVERAGE_PATH+"/coverage.json", newCoverageJson);
|
||||
})
|
||||
@@ -1,98 +0,0 @@
|
||||
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": "mlgljs"
|
||||
},
|
||||
"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-layer-style.json", function(req, res) {
|
||||
res.json(
|
||||
JSON.parse(
|
||||
fs.readFileSync(__dirname+"/example-layer-style.json").toString()
|
||||
)
|
||||
);
|
||||
})
|
||||
|
||||
app.get("/example-style.json", function(req, res) {
|
||||
res.json(
|
||||
JSON.parse(
|
||||
fs.readFileSync(__dirname+"/example-style.json").toString()
|
||||
)
|
||||
);
|
||||
})
|
||||
|
||||
|
||||
module.exports = app;
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"type":"FeatureCollection",
|
||||
"features":[
|
||||
{
|
||||
"type":"Feature",
|
||||
"properties": {
|
||||
"name": "Dinagat Islands"
|
||||
},
|
||||
"geometry":{
|
||||
"type": "Point",
|
||||
"coordinates": [125.6, 10.1]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
example: require("./example")
|
||||
};
|
||||
103
tsconfig.json
Normal file
103
tsconfig.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs", /* Specify what module code is generated. */
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
||||
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||
"resolveJsonModule": true, /* Enable importing .json files. */
|
||||
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
"noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user