Skip to content

Commit

Permalink
Merge branch 'main' into Feature/AccessibilityTable
Browse files Browse the repository at this point in the history
  • Loading branch information
raven-wing authored Jan 11, 2025
2 parents 6abaf22 + 3d8b1c7 commit a7dbe74
Show file tree
Hide file tree
Showing 16 changed files with 3,572 additions and 172 deletions.
13 changes: 12 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
python -m pip install --upgrade pip
pip install poetry==1.3
poetry install
cd tests/e2e_tests && npm install
- name: Run linters
run: make lint-check
- name: Run tests without coverage
Expand All @@ -46,5 +47,15 @@ jobs:
- name: Run e2e tests
run: |
PYTHONUNBUFFERED=1;FLASK_ENV=development;FLASK_APP="goodmap.goodmap:create_app(config_path='./tests/e2e_tests/e2e_test_config.yml')" poetry run flask run &
FLASK_PID=$!
sleep 3
cd tests/e2e_tests && node_modules/cypress/bin/cypress run --browser chromium
cd tests/e2e_tests && node_modules/cypress/bin/cypress run --browser chromium --spec cypress/e2e/basic-test/*
kill $FLASK_PID
- name: Generate e2e stress test data
run: |
python tests/e2e_tests/cypress/support/generate_stress_test_data.py
- name: Run e2e stress tests
run: |
PYTHONUNBUFFERED=1;FLASK_ENV=development;FLASK_APP="goodmap.goodmap:create_app(config_path='./tests/e2e_tests/e2e_stress_test_config.yml')" poetry run flask run &
sleep 3
cd tests/e2e_tests && node_modules/cypress/bin/cypress run --browser chromium --spec cypress/e2e/stress-test/*
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ data.json
config.yml
**/node_modules
tests/e2e_tests/cypress/screenshots/
**/package-lock.json
**/package.json


# coverage based artifacts
Expand All @@ -24,3 +22,6 @@ dist
# translation specific files
goodmap/locale/*/LC_MESSAGES/*.mo
*.pot

# e2e stress test files
e2e_stress_test_data.json
19 changes: 16 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
lint:
lint-fix:
poetry run black .
poetry run ruff check --fix .
cd tests/e2e_tests && npm run lint-fix
cd tests/e2e_tests && npm run prettier-fix

dev: lint
dev: lint-fix
poetry run pyright .

lint-check:
poetry run black --check .
poetry run ruff check .
poetry run pyright .
cd tests/e2e_tests && npm run lint
cd tests/e2e_tests && npm run prettier

unit-tests:
poetry run python -m pytest
Expand All @@ -17,7 +21,13 @@ unit-tests-no-coverage:
poetry run python -m pytest -m "skip_coverage"

e2e-tests:
cd tests/e2e_tests && node_modules/cypress/bin/cypress run --browser chromium
cd tests/e2e_tests && node_modules/cypress/bin/cypress run --browser chromium --spec cypress/e2e/basic-test/*

e2e-stress-tests-generate-data:
python tests/e2e_tests/cypress/support/generate_stress_test_data.py

e2e-stress-tests:
cd tests/e2e_tests && node_modules/cypress/bin/cypress run --browser chromium --spec cypress/e2e/stress-test/*

coverage:
poetry run coverage run --branch --source=goodmap -m pytest -m "not skip_coverage"
Expand All @@ -29,6 +39,9 @@ html-cov: coverage
run-e2e-env:
poetry run flask --app "goodmap.goodmap:create_app(config_path='tests/e2e_tests/e2e_test_config.yml')" --debug run

run-e2e-stress-env:
poetry run flask --app "goodmap.goodmap:create_app(config_path='tests/e2e_tests/e2e_stress_test_config.yml')" --debug run

verify-json-data:
ifndef JSON_DATA_FILE
$(error "Missing required argument JSON_DATA_FILE: make verify-json-data JSON_DATA_FILE=path/to/json")
Expand Down
8 changes: 8 additions & 0 deletions tests/e2e_tests/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
tabWidth: 4,
bracketSpacing: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
printWidth: 100,
};
117 changes: 60 additions & 57 deletions tests/e2e_tests/cypress/e2e/basic-test/commons.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,81 @@
export const expectedPlaceZwierzyniecka = {
title: "Zwierzyniecka",
subtitle: "small bridge",
categories: [
["type_of_place", "small bridge"],
["accessible_by", "bikes, pedestrians"]
]
title: 'Zwierzyniecka',
subtitle: 'small bridge',
categories: [
['type_of_place', 'small bridge'],
['accessible_by', 'bikes, pedestrians'],
],
};

// This is workaround for a problem with getting specific marker.
// TODO Find a way of getting specific marker or marker in specific position
export function getRightmostMarker(markers) {
let rightmostMarker;
let maxX = -Infinity;
let rightmostMarker;
let maxX = -Infinity;

Cypress.$(markers).each((index, marker) => {
const rect = marker.getBoundingClientRect();
if (rect.x > maxX) {
maxX = rect.x;
rightmostMarker = marker;
}
});
return rightmostMarker;
Cypress.$(markers).each((index, marker) => {
const rect = marker.getBoundingClientRect();
if (rect.x > maxX) {
maxX = rect.x;
rightmostMarker = marker;
}
});
return rightmostMarker;
}

export function verifyPopupContent(expectedContent) {
cy.get('.point-title').should('have.text', expectedContent.title);
cy.get('.point-title').should('have.text', expectedContent.title);

cy.get('.point-subtitle').should('have.text', expectedContent.subtitle);
cy.get('.point-subtitle').should('have.text', expectedContent.subtitle);

expectedContent.categories.forEach(([category, value]) => {
cy.contains(category).should('exist');
cy.contains(value).should('exist');
});
expectedContent.categories.forEach(([category, value]) => {
cy.contains(category).should('exist');
cy.contains(value).should('exist');
});

if (expectedContent.CTA) {
cy.contains(expectedContent.CTA.displayValue).should('exist');
cy.contains('button', expectedContent.CTA.displayValue).click();
cy.get('@openStub').should('have.been.calledOnceWith',
expectedContent.CTA.value, '_blank');
}
if (expectedContent.CTA) {
cy.contains(expectedContent.CTA.displayValue).should('exist');
cy.contains('button', expectedContent.CTA.displayValue).click();
cy.get('@openStub').should('have.been.calledOnceWith', expectedContent.CTA.value, '_blank');
}
}

export function verifyProblemForm() {
cy.contains('report a problem').should('exist').click();
cy.intercept('POST', '/api/report-location').as('reportLocation');
cy.contains('report a problem').should('exist').click();
cy.intercept('POST', '/api/report-location').as('reportLocation');

cy.get('form').should('exist').within(() => {
cy.get('select').should('exist').within(() => {
cy.get('option').then((options) => {
const optionValues = [...options].map(option => option.textContent.trim());
expect(optionValues).to.include.members([
'--Please choose an option--',
'this point is not here',
"it's overloaded",
"it's broken",
'other',
]);
});
});
cy.get('form')
.should('exist')
.within(() => {
cy.get('select')
.should('exist')
.within(() => {
cy.get('option').then(options => {
const optionValues = [...options].map(option => option.textContent.trim());
expect(optionValues).to.include.members([
'--Please choose an option--',
'this point is not here',
"it's overloaded",
"it's broken",
'other',
]);
});
});

cy.get('select').select('other');
cy.get('input[name="problem"]').should('exist');
cy.get('input[name="problem"]').type('Custom issue description');
cy.get('input[type="submit"]').should('exist').click();
});
cy.get('select').select('other');
cy.get('input[name="problem"]').should('exist');
cy.get('input[name="problem"]').type('Custom issue description');
cy.get('input[type="submit"]').should('exist').click();
});

cy.wait('@reportLocation').then((interception) => {
expect(interception.request.body).to.have.property('id');
expect(interception.request.body).to.have.property('description');
expect(interception.request.body.description).to.equal('Custom issue description');
expect(interception.response.statusCode).to.equal(200);
expect(interception.response.body.message).to.equal('Location reported');
});
cy.wait('@reportLocation').then(interception => {
expect(interception.request.body).to.have.property('id');
expect(interception.request.body).to.have.property('description');
expect(interception.request.body.description).to.equal('Custom issue description');
expect(interception.response.statusCode).to.equal(200);
expect(interception.response.body.message).to.equal('Location reported');
});

cy.contains('p', 'Location reported').should('exist');
cy.get('form').should('not.exist');
cy.contains('p', 'Location reported').should('exist');
cy.get('form').should('not.exist');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Checks whether map has moved to the correct location by checking
// if the specific OSM (Open Street Map) tile file was requested.
// Filename (URL) format is /zoom/column/tile.png
// Formulas that calculate tiles and columns can be found here:
// https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Common_programming_languages
function lon2column(lon, zoom) {
return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom));
}
function lat2tile(lat, zoom) {
return Math.floor(
((1 -
Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) /
Math.PI) /
2) *
Math.pow(2, zoom),
);
}

let mockedLon = 15.976627;
let mockedLat = 51.919126;

describe('Go To My Location Button', () => {
beforeEach(() => {
cy.visit('/', {
onBeforeLoad(win) {
cy.stub(win.navigator.geolocation, 'watchPosition').callsFake(success => {
success({
coords: {
longitude: mockedLon,
latitude: mockedLat,
accuracy: 100,
},
});
});
},
});
});

it('should click the go-to-my-location button and move the map', () => {
cy.window().then(win => {
win.navigator.permissions.query = () =>
Promise.resolve({
state: 'granted',
});
});
cy.get('.leaflet-marker-icon').click();

cy.get('.MuiButtonBase-root > [data-testid="MyLocationIcon"] > path').click();
cy.get('.MuiButtonBase-root > [data-testid="MyLocationIcon"] > path').click();

const zoomLevel = 16;
const OSMColumn = lon2column(mockedLon, zoomLevel);
const OSMTile = lat2tile(mockedLat, zoomLevel);

const regExpURL = new RegExp(
`^https://[abc]\\.tile\\.openstreetmap\\.org/${zoomLevel}/${OSMColumn}/${OSMTile}\\.png$`,
);
cy.intercept('GET', regExpURL).as('tileRequest');
cy.wait('@tileRequest', { timeout: 10000 }).then(interception => {
expect(interception.response.statusCode).to.eq(200);
expect(interception.request.url).to.include(`${OSMColumn}/${OSMTile}.png`);
});
});
});
35 changes: 17 additions & 18 deletions tests/e2e_tests/cypress/e2e/basic-test/map-test.cy.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
describe('Map Tests', () => {
beforeEach(() => {
cy.visit('/')
})
beforeEach(() => {
cy.visit('/');
});

it('displays filter list with two categories with 5 items', () => {
cy.get('input[type="checkbox"]').should('have.length', 5)
cy.get('form span').should('have.length', 2)
})
it('displays filter list with two categories with 5 items', () => {
cy.get('input[type="checkbox"]').should('have.length', 5);
cy.get('form span').should('have.length', 2);
});

it('Should not have scrollbars', () => {
// Get the dimensions of the viewport and the entire page
cy.window().then((win) => {
const { innerWidth, innerHeight } = win;
const { scrollWidth, scrollHeight } = win.document.documentElement;
it('Should not have scrollbars', () => {
// Get the dimensions of the viewport and the entire page
cy.window().then(win => {
const { innerWidth, innerHeight } = win;
const { scrollWidth, scrollHeight } = win.document.documentElement;

// Assert if the page width or height is less than or equal to the viewport dimensions,
// indicating no scrollbars
expect(scrollWidth <= innerWidth && scrollHeight <= innerHeight).to.be.true;
// Assert if the page width or height is less than or equal to the viewport dimensions,
// indicating no scrollbars
expect(scrollWidth <= innerWidth && scrollHeight <= innerHeight).to.be.true;
});
});
});
}
)
});
Loading

0 comments on commit a7dbe74

Please sign in to comment.