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

Change contentPreference from single- to multi-select. #78

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 12 additions & 8 deletions .github/workflows/ci-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ jobs:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: latest
# - run: sudo apt-get install xvfb
# - run: npm install
# - run: npx playwright install
# - run: xvfb-run --auto-servernum -- npm test
env:
CI: true
with:
node-version: latest
- name: Install XVFB
run: sudo apt-get install -y xvfb
- name: Install Dependencies
run: npm install
- name: Install Playwright
run: npx playwright install
- name: Run Tests with XVFB
run: xvfb-run --auto-servernum -- npm test
env:
CI: true
3 changes: 1 addition & 2 deletions src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ chrome.runtime.onInstalled.addListener(async () => {
featureIndexOverlayOption: false,
renderMap: true,
defaultExtCoor: 'pcrs',
defaultLocCoor: 'gcrs',
defaultContentPreference: 'no-preference'
defaultLocCoor: 'gcrs'
}
});
registerContentScripts();
Expand Down
6 changes: 2 additions & 4 deletions src/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,10 @@ <h6 class="card-title">Accessibility Settings</h6>
<h6 class="card-title">Content Preferences</h6>
<div>
<label class="form-label" for="content-prefs">Preferred map content type: </label>
<select class="form-select form-select-sm" id="contentPreference">
<option value="no-preference" selected>No preference (default)</option>
<select class="form-select form-select-sm" multiple id="contentPreference">
<option value="image">Images</option>
<option value="tiled-image">Tiled images</option>
<option value="tile">Tiles</option>
<option value="feature">Features</option>
<option value="vector-tile">Vector tiles</option>
<option value="table">Tables</option>
</select>
</div>
Expand Down
18 changes: 15 additions & 3 deletions src/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ function loadOptions() {
featureIndexOverlayOption: false,
renderMap: false,
defaultExtCoor: 'pcrs',
defaultLocCoor: 'gcrs',
defaultContentPreference: 'no-preference'
defaultLocCoor: 'gcrs'
};
for (let name in options) {
let elem = document.getElementById(name);
Expand All @@ -36,6 +35,15 @@ function loadOptions() {
Array.from(elem.children).forEach(el => el.value === options[name]?
el.selected = true : el.selected = false);
break;
case "object":
if (Array.isArray(options[name])) {
Array.from(elem.children).forEach(o => {
if (options[name].includes(o.value)) {
o.defaultSelected = true;
}
});
}
break;
}
}
}
Expand All @@ -55,7 +63,11 @@ function handleCheckboxChange(e) {

function handleDropdownChange(e) {
let option = e.target.id;
options[option] = Array.from(e.target.children).find(el => el.selected).value;
if (option === 'contentPreference') {
options[option] = Array.from(e.target.children).filter(el => el.selected).map( el => el.value);
} else {
options[option] = Array.from(e.target.children).find(el => el.selected).value;
}
saveOptions();
}

Expand Down
6 changes: 5 additions & 1 deletion test/e2e/basics/locale.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<html>
<!-- the lang attribute, exceptionally in en and fr now force the map locale -->
<!-- consequently, to test correct localization / internationalization
remove the lang attribute, or change it to something not en or fr,
map will use the locale strings injected by the extension -->

<head>
<title>Static Features Test</title>
Expand Down
28 changes: 14 additions & 14 deletions test/e2e/basics/locale.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,44 +38,44 @@ test.describe("Locale Tests", () => {
expect(zoomInTitle).toBe("Zoom in");
expect(zoomOutTitle).toBe("Zoom out");
expect(reloadTitle).toBe("Reload");
expect(fullScreenTitle).toBe("View Fullscreen");
expect(fullScreenTitle).toBe("View fullscreen");
});
});

test.describe("Other Locale Tests", () => {
let frContext, frPage;
let svContext, svPage;
test.beforeAll(async () => {
let pathToExtension = path.join(__dirname, '../../../src/');

frContext = await chromium.launchPersistentContext("",{
// update to swedish because en and fr locales are 'forced' by the lang attribute
svContext = await chromium.launchPersistentContext("",{locale: 'sv',
headless: false,
slowMo: 50,
args: [
'--lang=fr',
'--lang=sv',
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`
],
]
});
let [background] = frContext.serviceWorkers();
let [background] = svContext.serviceWorkers();
if (!background)
background = await frContext.waitForEvent("serviceworker");
background = await svContext.waitForEvent("serviceworker");
const id = background.url().split("/")[2];
let newPage = await frContext.newPage();
let newPage = await svContext.newPage();
await newPage.goto('chrome-extension://' + id +'/popup.html', {waitUntil: "load"});
frPage = await frContext.newPage();
await frPage.goto("test/e2e/basics/locale.html", {waitUntil: "load"});
svPage = await svContext.newPage();
await svPage.goto("test/e2e/basics/locale.html", {waitUntil: "load"});
});

test.afterAll(async () => {
await frContext.close();
await svContext.close();
});

test("UI button titles", async () => {
let reloadTitle = await frPage.$eval(
let reloadTitle = await svPage.$eval(
"xpath=//html/body/mapml-viewer >> css=div > div.leaflet-control-container > div.leaflet-top.leaflet-left > div.mapml-reload-button.leaflet-bar.leaflet-control > button",
(tile) => tile.title
);

expect(reloadTitle).toBe("Rechargez");
expect(reloadTitle).toBe("Läs In Igen");
});
});
8 changes: 6 additions & 2 deletions test/e2e/basics/popup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,18 @@ test.describe("Popup test", () => {

let newPage = await context.newPage();
await newPage.goto("test/e2e/basics/popup.test.html", { waitUntil: "load" });
newPage.waitForTimeout(500);
await newPage.waitForTimeout(1000);
await newPage.click("body > mapml-viewer");
await newPage.keyboard.press("Shift+F10");
await newPage.keyboard.press("Tab");
await newPage.waitForTimeout(100);
await newPage.keyboard.press("Enter");
await newPage.keyboard.press("Tab");
await newPage.waitForTimeout(100);
await newPage.keyboard.press("Tab");
await newPage.waitForTimeout(100);
await newPage.keyboard.press("Enter");
await newPage.waitForTimeout(100);

const text = await newPage.evaluate(() => navigator.clipboard.readText());
const coordinates = await newPage.evaluate((t) => {
Expand All @@ -119,7 +123,7 @@ test.describe("Popup test", () => {

let newPage = await context.newPage();
await newPage.goto("test/e2e/basics/popup.test.html", { waitUntil: "load" });
newPage.waitForTimeout(500);
await newPage.waitForTimeout(500);
await newPage.click("body > mapml-viewer");
await newPage.keyboard.press("Shift+F10");
await newPage.keyboard.press("Tab");
Expand Down
19 changes: 18 additions & 1 deletion test/e2e/basics/preferred-content.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,26 @@
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Preferred Content Test</title>
<script type="module" src="../../../src/dist/mapml.js"></script>
<script>
document.addEventListener('DOMContentLoaded',(e)=>{
let l, map = document.querySelector('mapml-viewer'),
prefersEverything = map.matchMedia('(prefers-map-content: image) and (prefers-map-content: tile) and (prefers-map-content: feature) and (prefers-map-content: table)').matches === 'true',
t = document.querySelector('template'),
prefersFeaturesOnly = map.matchMedia('(prefers-map-content: feature) and ( not ((prefers-map-content: image) or (prefers-map-content: tile)))').matches === 'true',
prefersTiles = map.matchMedia('(prefers-map-content: tile');
if (prefersFeaturesOnly) {
l = t.content.querySelector('#features').cloneNode(true);
} else if (prefersImages) {
l = t.content.querySelector('#wms').cloneNode(true);
} else if (prefersTiles) {
l = t.content.querySelector('#tiles').cloneNode(true);
}
map.appendChild(l);
});
</script>
</head>
<body>
<mapml-viewer style="height: 500px;width:500px;" projection="CBMTILE" zoom="8" lat="46.51231982020816" lon="-63.25669692277839" controls>
<mapml-viewer data-testid="viewer" style="height: 500px;width:500px;" projection="CBMTILE" zoom="8" lat="46.51231982020816" lon="-63.25669692277839" controls>
<map-layer data-testid="test-layer" label="Provinces and Territories" src="../data/cbmt-cbmtile.mapml" checked></map-layer>
</mapml-viewer>
</body>
Expand Down
52 changes: 52 additions & 0 deletions test/e2e/basics/preferred-content.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ test.describe("Preferred content test", () => {
test("User prefers feature content type", async () => {
// "page" is the extension popup, hasn't been closed so still open in a
// browser tab somewhere...
await page.bringToFront();
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
Expand All @@ -55,5 +56,56 @@ test.describe("Preferred content test", () => {
const label = await layer.evaluate((l) => l._layerControlLabel.textContent);
expect(label).toEqual('Feature content');
});

test("Multiple preferences can be expressed by user", async () => {
await page.bringToFront();
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
// features is currently selected, so need a tricky set of key presses
await page.keyboard.press("ArrowUp");
await page.keyboard.press("ArrowUp");
await page.keyboard.press("Shift+ArrowDown");
await page.keyboard.press("Shift+ArrowDown");
await page.keyboard.press("Shift+ArrowDown");
let newPage = await context.newPage();
await newPage.goto("test/e2e/basics/preferred-content.html", { waitUntil: "domcontentloaded" });
await newPage.waitForTimeout(1000);
let map = newPage.getByTestId('viewer');
const matches = await map.evaluate((map)=>{
return map.matchMedia('(prefers-map-content: image) and (prefers-map-content: tile) and (prefers-map-content: feature) and (prefers-map-content: table)').matches;
});
expect(matches).toBe(true);
});
test("Multiple disjoint preferences can be expressed by user", async () => {
await page.bringToFront();
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("ArrowUp");
await page.keyboard.press("ArrowUp");
await page.keyboard.press(" "); // select tiles option
await page.keyboard.press("Control+ArrowDown");
await page.keyboard.press("Control+ArrowDown");
await page.keyboard.press(" "); // select tables option
let newPage = await context.newPage();
await newPage.goto("test/e2e/basics/preferred-content.html", { waitUntil: "domcontentloaded" });
await newPage.waitForTimeout(1000);
let map = newPage.getByTestId('viewer');
const matches = await map.evaluate((map)=>{
return map.matchMedia('(not (prefers-map-content: image)) and (prefers-map-content: tile) and (not (prefers-map-content: feature)) and (prefers-map-content: table)').matches;
});
expect(matches).toBe(true);
});

});
26 changes: 1 addition & 25 deletions test/e2e/basics/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ test.describe("Render MapML resources test", () => {
await page.keyboard.press("Equal");
await page.waitForTimeout(1000);
}
await page.waitForTimeout(500);
await page.waitForTimeout(1000);
expect(page.url()).toContain("#5,-89.7827040843159,60.27815582468662");
await page.goBack({waitUntil: "networkidle"});
expect(page.url()).toContain("about:blank");
Expand Down Expand Up @@ -79,14 +79,6 @@ test.describe("Render MapML resources test", () => {
});

test("Render map from text/mapml document", async () => {
//Changes page.goto response (initial page load) to be of content type text/mapml
await page.route("test/e2e/basics/test.mapml", async route => {
const response = await page.request.fetch("test/e2e/basics/test.mapml");
await route.fulfill({
body: await response.body(),
contentType: 'text/mapml'
});
});
await page.goto("test/e2e/basics/test.mapml");
const map = await page.waitForFunction(() => document.querySelector("mapml-viewer"));

Expand Down Expand Up @@ -134,29 +126,13 @@ test.describe("Render MapML resources test", () => {
});

test("Projection defaults to OSMTILE in the case of unknown projection", async () => {
//Changes page.goto response (initial page load) to be of content type text/mapml
await page.route("test/e2e/basics/unknown_projection.mapml", async route => {
const response = await page.request.fetch("test/e2e/basics/unknown_projection.mapml");
await route.fulfill({
body: await response.body(),
contentType: 'text/mapml'
});
});
await page.goto("test/e2e/basics/unknown_projection.mapml");
const map = await page.waitForFunction(() => document.querySelector("mapml-viewer"));
const projection = await map.getAttribute('projection');
expect(projection).toEqual("OSMTILE");
}, {times: 1});

test.skip("Projection from map-meta[content*=projection] attribute / mime type parameter", async () => {
//Changes page.goto response (initial page load) to be of content type text/mapml
await page.route("test/e2e/basics/content-type-projection.mapml", async route => {
const response = await page.request.fetch("test/e2e/basics/content-type-projection.mapml");
await route.fulfill({
body: await response.body(),
contentType: 'text/mapml'
});
});
await page.waitForTimeout(1000);
await page.goto("test/e2e/basics/content-type-projection.mapml");
await page.waitForTimeout(1000);
Expand Down
Loading