Skip to content

Commit

Permalink
PW tests for zoom controls and centering (#639)
Browse files Browse the repository at this point in the history
* tests for events should be controlled with deepest event nodes

* center viewport tests

* split zoom tests

* zoom tests

* fix  _ - , also add 0.01 max mismatch ratio for screnshot

* forgot to include gitignore for pngs

* code style fix
  • Loading branch information
mudhoney authored Nov 1, 2024
1 parent 401d733 commit a5977c3
Show file tree
Hide file tree
Showing 8 changed files with 397 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ node_modules
/playwright-report/
/blob-report/
/playwright/.cache/
*.png
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { test, expect } from "@playwright/test";
import { Helioviewer } from "../../../page_objects/helioviewer";
import { mockEvents } from "../../../utils/events";
import { readFile } from "fs/promises";

/**
* This test mocks some random events for CCMC
* then selects some specific event instances,
* then asserts all event markers for matching event instances, should be visible
* also asserts all of the other nodes, should be unchecked
*/
test("Event instances should control visibility of event markers", async ({ page, browser }, info) => {
// mocked event data
const events = {
CCMC: {
aet1: {
aet1frm1: {
aet1frm1ei1: {},
aet1frm1ei2: {}
}
},
bet2: {
bet2frm1: {
bet2frm1ei1: {},
bet2frm1ei2: {},
bet2frm1ei3: {}
},
bet2frm2: {
bet2frm2ei1: {},
bet2frm2ei2: {}
}
}
}
};

// mock events
await mockEvents(page, events);

// load helioviewer
let hv = new Helioviewer(page, info);

// Action 1 : BROWSE TO HELIOVIEWER
await hv.Load();
await hv.CloseAllNotifications();

// Action 2 : Open left sources panel
await hv.OpenSidebar();

// Parse event tree pieces
const ccmc = hv.parseTree("CCMC");

// Action 3 : Open up all frm branches
await ccmc.toggleBranchFRM("aet1", "aet1frm1");
await ccmc.toggleBranchFRM("bet2", "bet2frm1");
await ccmc.toggleBranchFRM("bet2", "bet2frm2");

// Action 4: Select some of the event instances
await ccmc.toggleCheckEventInstance("aet1", "aet1frm1", "aet1frm1ei2");
await ccmc.toggleCheckEventInstance("bet2", "bet2frm1", "bet2frm1ei3");
await ccmc.toggleCheckEventInstance("bet2", "bet2frm2", "bet2frm2ei1");

// Action 5: Assert all event markers belong to matching event instances should be visible,
await ccmc.assertEventVisible("aet1frm1ei2");
await ccmc.assertEventVisible("bet2frm1ei3");
await ccmc.assertEventVisible("bet2frm2ei1");

// Action 6: Assert all event markers DOES NOT belong to matching event instances should NOT be visible,
await ccmc.assertEventNotVisible("aet1frm1ei1");
await ccmc.assertEventNotVisible("bet2frm1ei1");
await ccmc.assertEventNotVisible("bet2frm1ei2");
await ccmc.assertEventNotVisible("bet2frm2ei2");

// Action 7: Select again same event instances to not to select them
await ccmc.toggleCheckEventInstance("aet1", "aet1frm1", "aet1frm1ei2");
await ccmc.toggleCheckEventInstance("bet2", "bet2frm1", "bet2frm1ei3");
await ccmc.toggleCheckEventInstance("bet2", "bet2frm2", "bet2frm2ei1");

// Action 8: Now matching markers should NOT be visible
await ccmc.assertEventNotVisible("aet1frm1ei2");
await ccmc.assertEventNotVisible("bet2frm1ei3");
await ccmc.assertEventNotVisible("bet2frm2ei1");
});
78 changes: 78 additions & 0 deletions tests/desktop/normal/zoom/center_image.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { test, expect } from "@playwright/test";
import { Helioviewer } from "../../../page_objects/helioviewer";

/**
* This test;
* - load helioviewer
* - take screenshot
* - drag sun to random place
* - press c to center sun
* - centered sun should match initial sun
*/
test("Pressing C should center sun", async ({ page }, info) => {
let hv = new Helioviewer(page, info);

// 1. LOAD HV
await hv.Load();
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 2. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 3. TAKE A SCREENSHOT
const initialCenteredSun = await hv.sunScreenshot();

// 4. NOW PULL PAGE TO SOMEWHERE
await hv.moveViewport(300, 30);

// 5. CENTER VIEWPORT WITH PRESSING C
await page.keyboard.press("c");

// 6. TAKE ANOTHER SCREENSHOT
const centeredWithKeyboard = await hv.sunScreenshot();

// 7. BOTH SCREENSHOT SHOULD MATCH

expect(initialCenteredSun).toBe(centeredWithKeyboard);
});

/**
* This test;
* - load helioviewer
* - take screenshot
- drag sun to random place
- press sun center button to center sun
- centered sun should match initial sun
*/
test("Pressing sun center button should center sun", async ({ page }, info) => {
let hv = new Helioviewer(page, info);

// 1. LOAD HV
await hv.Load();
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 2. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 3. TAKE A SCREENSHOT
const initialCenteredSun = await hv.sunScreenshot();

// 4. NOW PULL PAGE TO SOMEWHERE
await hv.moveViewport(300, 30);

// 5. CENTER VIEWPORT WITH PRESSING SUN CENTER BuTTON
await hv.centerViewport();

// 6. TAKE ANOTHER SCREENSHOT
const centeredWithButton = await hv.sunScreenshot();

// 7. BOTH SCREENSHOT SHOULD MATCH

expect(initialCenteredSun).toBe(centeredWithButton);
});
100 changes: 100 additions & 0 deletions tests/desktop/normal/zoom/zoom_in.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { test, expect } from "@playwright/test";
import { Helioviewer } from "../../../page_objects/helioviewer";

/**
* This test tests zoom out functionality with
* - load helioviewer
* - zoom one in
* - take screenshot
* - load helioviewer with clean state, with ?imageScale=2.42044088 indicating zoom 1 in scale value
* - screenshot should match previous screenshot
*/
test("Pressing zoom in button should zoom sun in", async ({ page }, info) => {
let hv = new Helioviewer(page, info);

// 1. LOAD HV
await hv.Load();
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 2. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 3. ZOOM ONE IN
await hv.ZoomIn(1);
await hv.WaitForLoadingComplete();

// 4. TAKE A SCREENSHOT
await hv.sunScreenshot("zoom-one-in-with-button-screenshot.png");

// 5. LOAD HELIOVIEWER WITH CLEAN STATE, WITH ?IMAGESCALE=2.42044088 INDICATING ZOOM 1 IN SCALE VALUE
await page.evaluate(() => localStorage.clear());
await hv.Load("/?imageScale=2.42044088");
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 6. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 7. TAKE ANOTHER SCREENSHOT
const zoomOneInWithURL = await hv.sunScreenshot("zoom-one-in-with-url-screenshot");

// 8. BOTH SCREENSHOT SHOULD MATCH
expect(Buffer.from(zoomOneInWithURL, "base64")).toMatchSnapshot("zoom-one-in-with-button-screenshot.png", {
maxDiffPixelRatio: 0.01
});
});

/**
* This test;
* - load helioviewer
* - zoom one in with keyboard + char
* - take screenshot
* - load helioviewer with clean state, with ?imageScale=9.68176352 indicating zoom 1 in scale value
* - screenshot should match previous screenshot
*/
test("Pressing zoom in with keyboard + should zoom sun in", async ({ page }, info) => {
let hv = new Helioviewer(page, info);

// 1. LOAD HV
await hv.Load();
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 2. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

await hv.sunScreenshot("initial.png");

// 3. ZOOM ONE IN WITH KEYBOARD "+"
await page.keyboard.press("+");
await hv.WaitForLoadingComplete();

// 4. TAKE A SCREENSHOT
await hv.sunScreenshot("zoom-one-in-with-keyboard-screenshot.png");

// 5. LOAD HELIOVIEWER WITH CLEAN STATE, WITH ?IMAGESCALE=9.68176352 INDICATING ZOOM 1 OUT SCALE VALUE
await page.evaluate(() => localStorage.clear());
await hv.Load("/?imageScale=2.42044088");
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 6. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 7. TAKE ANOTHER SCREENSHOT
const zoomOneInWithURL = await hv.sunScreenshot("zoom-one-in-with-url-screenshot");

// 8. BOTH SCREENSHOT SHOULD MATCH
expect(Buffer.from(zoomOneInWithURL, "base64")).toMatchSnapshot("zoom-one-in-with-keyboard-screenshot.png", {
maxDiffPixelRatio: 0.01
});
});
98 changes: 98 additions & 0 deletions tests/desktop/normal/zoom/zoom_out.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { test, expect } from "@playwright/test";
import { Helioviewer } from "../../../page_objects/helioviewer";

/**
* This test;
* - load helioviewer
* - zoom one out with button
* - take screenshot
* - load helioviewer with clean state, with ?imageScale=9.68176352 indicating zoom 1 out scale value
* - screenshot should match previous screenshot
*/
test("Pressing zoom out button should zoom sun out", async ({ page }, info) => {
let hv = new Helioviewer(page, info);

// 1. LOAD HV
await hv.Load();
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 2. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 3. ZOOM ONE OUT WITH BUTTON
await hv.ZoomOut(1);
await hv.WaitForLoadingComplete();

// 4. TAKE A SCREENSHOT
await hv.sunScreenshot("zoom-one-out-with-button-screenshot.png");

// 5. LOAD HELIOVIEWER WITH CLEAN STATE, WITH ?IMAGESCALE=9.68176352 INDICATING ZOOM 1 OUT SCALE VALUE
await page.evaluate(() => localStorage.clear());
await hv.Load("/?imageScale=9.68176352");
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 6. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 7. TAKE ANOTHER SCREENSHOT
const zoomOneOutWithURL = await hv.sunScreenshot("zoom-one-out-with-url-screenshot");

// 8. BOTH SCREENSHOT SHOULD MATCH
expect(Buffer.from(zoomOneOutWithURL, "base64")).toMatchSnapshot("zoom-one-out-with-button-screenshot.png", {
maxDiffPixelRatio: 0.01
});
});

/**
* This test;
* - load helioviewer
* - zoom one out with keyboard - char
* - take screenshot
* - load helioviewer with clean state, with ?imageScale=9.68176352 indicating zoom 1 out scale value
* - screenshot should match previous screenshot
*/
test("Pressing zoom out with keyboard - should zoom sun out", async ({ page }, info) => {
let hv = new Helioviewer(page, info);

// 1. LOAD HV
await hv.Load();
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 2. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 3. ZOOM ONE OUT WITH KEYBOARD "-"
await page.keyboard.press("-");
await hv.WaitForLoadingComplete();

// 4. TAKE A SCREENSHOT
await hv.sunScreenshot("zoom-one-out-with-keyboard-screenshot.png");

// 5. LOAD HELIOVIEWER WITH CLEAN STATE, WITH ?IMAGESCALE=9.68176352 INDICATING ZOOM 1 OUT SCALE VALUE
await page.evaluate(() => localStorage.clear());
await hv.Load("/?imageScale=9.68176352");
await hv.CloseAllNotifications();
await hv.OpenSidebar();

// 6. GO NEWEST IMAGE
await hv.UseNewestImage();
await hv.WaitForLoadingComplete();
await hv.CloseAllNotifications();

// 7. TAKE ANOTHER SCREENSHOT
const zoomOneOutWithURL = await hv.sunScreenshot("zoom-one-out-with-url-screenshot");

// 8. BOTH SCREENSHOT SHOULD MATCH
expect(Buffer.from(zoomOneOutWithURL, "base64")).toMatchSnapshot("zoom-one-out-with-keyboard-screenshot.png", {
maxDiffPixelRatio: 0.01
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { test, expect } from "@playwright/test";
import { Helioviewer } from "../../page_objects/helioviewer";
import { Helioviewer } from "../../../page_objects/helioviewer";

/**
* This test simply adds and removes images layers
Expand Down
15 changes: 15 additions & 0 deletions tests/page_objects/event_tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,21 @@ class EventTree {
await expect(eventFRMNode).toHaveClass(/jstree-unchecked/);
}

/**
* This function checks if the given frm node is halfchecked (not all of its childrens are selected) in event tree.
* @param {string} frm, The frm name pointing to the node in tree (e.g. "NOAA SWPC Observer", "SPoCA").
* @return {Promise<void>} A promise for you to wait for assertion to complete.
*/
async assertFrmNodeHalfChecked(event_type: string, frm: string): Promise<void> {
const eventTypeLink = this.page.getByRole("link", { name: EventTree.makeNumericRegex(event_type) });
const eventTypeNode = await this.root.getByRole("listitem").filter({ has: eventTypeLink });

const eventFRMLink = this.page.getByRole("link", { name: EventTree.makeNumericRegex(frm) });
const eventFRMNode = await eventTypeNode.getByRole("listitem").filter({ has: eventFRMLink });

await expect(eventFRMNode).toHaveClass(/jstree-undetermined/);
}

/**
* This function checks if the given event instance node is unchecked in event tree.
* @param {string} event_type, The event type name pointing to the node in tree (e.g. "Active Region", "Corona Hole").
Expand Down
Loading

0 comments on commit a5977c3

Please sign in to comment.