Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace WebDriverIO with Cypress #831

Merged
merged 19 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 12 additions & 43 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ public
/errorShots
/old
/build
/cypress/screenshots
51 changes: 0 additions & 51 deletions config/wdio.conf.js

This file was deleted.

4 changes: 1 addition & 3 deletions config/webpack.production.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
},
Expand Down
6 changes: 2 additions & 4 deletions config/webpack.profiling.config.js
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
9 changes: 9 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "cypress";

export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
});
41 changes: 41 additions & 0 deletions cypress/e2e/accessibility.cy.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 170 additions & 0 deletions cypress/e2e/driver.ts
Original file line number Diff line number Diff line change
@@ -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');
}


}
Loading
Loading