Skip to content

playwright survey tests #9761

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

Merged
merged 11 commits into from
Apr 21, 2025
23 changes: 22 additions & 1 deletion e2e/helper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Page } from "@playwright/test";
import type { Locator, Page } from "@playwright/test";
import { expect } from "@playwright/test";

const environment = process.env.env;
Expand Down Expand Up @@ -124,4 +124,25 @@ export async function setRowItemFlowDirection(page) {
await page.evaluate(() => {
window["Survey"].settings.itemFlowDirection = "row";
});
}

export async function visibleInViewport (page, locator: Locator) {
const rect = await locator.boundingBox();
return await page.evaluate((rect) => {
return (
rect?.y >= 0 &&
rect?.x >= 0 &&
rect?.y + rect?.height <= (window.innerHeight || document.documentElement.clientHeight) &&
rect?.x + rect?.width <= (window.innerWidth || document.documentElement.clientWidth)
);
}, rect);
}
export async function expectHaveClasses(locator: Locator, className: string) {
// get current classes of element
const attrClass = await locator.getAttribute("class");
const elementClasses: string[] = attrClass ? attrClass.split(" ") : [];
const targetClasses: string[] = className.split(" ");
// Every class should be present in the current class list
const isValid = targetClasses.every(classItem => elementClasses.indexOf(classItem) > -1);
return isValid;
}
127 changes: 127 additions & 0 deletions e2e/survey/afterRenderEvent.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { test, expect } from "@playwright/test";
import { frameworks, url, initSurvey } from "../helper";

const title = "afterRenderQuestionEvent";

async function checkResizeObserverExists(page, modelName) {
return await page.evaluate((modelName) => {
return !!window[modelName].resizeObserver;
}, modelName);
}

frameworks.forEach((framework) => {
test.describe(`${framework} ${title}`, () => {
test.beforeEach(async ({ page }) => {
await page.goto(`${url}${framework}`);
});

test("afterRender is not fired when questions are lazy rendered", async ({ page }) => {
await page.goto(`${url}${framework}`);
await page.setViewportSize({ width: 1920, height: 1080 });
await page.evaluate(() => {
(window as any).Survey.settings.lazyRowsRendering = true;
});
const json = {
pages: [
{
name: "page1",
title: "page one",
elements: [
{ type: "radiogroup", name: "q1", choices: ["1", "2", "3"], },
{ type: "text", visibleIf: "{q1} = '1'", name: "q2", isRequired: true, },
{ type: "text", name: "q3", },
{ type: "text", name: "q4", }
],
},
],
};
await initSurvey(page, framework, {});
await page.evaluate((json) => {
window["survey"].onAfterRenderQuestion.add((_, options) => {
options.htmlElement.setAttribute("test", "true");
});
window["survey"].fromJSON(json);
}, json);

await page.locator("label").first().click();
await expect(page.locator("div[data-name='q1']")).toHaveAttribute("test", "true");
await expect(page.locator("div[data-name='q2']")).toHaveAttribute("test", "true");
await expect(page.locator("div[data-name='q3']")).toHaveAttribute("test", "true");
await expect(page.locator("div[data-name='q4']")).toHaveAttribute("test", "true");
});

test("afterRenderQuestion fires for initially hidden questions", async ({ page }) => {
const yesChoiceSelector = page.locator("label").filter({ hasText: "Yes" }).locator("span").first();

const json = {
pages: [
{
elements: [
{
name: "question4a",
type: "radiogroup",
title: "4 (a) question 4a ",
choices: [
{ text: "Yes", value: "valueYes", },
{ text: "No", value: "valueNo", },],
},
{
name: "question4b",
visibleIf: "{question4a} = 'valueYes'",
type: "radiogroup",
title: "4 (b) Test question 4b",
choices: [
{ text: "Yes", value: "BA17018_02_01", },
{ text: "No", value: "BA17018_02_02", },
],
},
],
name: "sectionTest",
},
],
title: "Test Sample",
};
await initSurvey(page, framework, {});
await page.evaluate((json) => {
window["survey"].onAfterRenderQuestion.add((_, options) => {
if (options.question.name == "question4a") {
var title = options.htmlElement.querySelector("input[value='valueYes']");
title.style.color = "tomato";
}
if (options.question.name == "question4b") {
options.htmlElement.style.border = "1px solid #CCC";
}
});
window["survey"].fromJSON(json);
}, json);

const questionSelector = page.locator(".sd-question");

await expect(questionSelector).toHaveCount(1);
await yesChoiceSelector.click();

await expect(questionSelector).toHaveCount(2);
await expect(page.locator("input[value='valueYes']")).toHaveCSS("color", "rgb(255, 99, 71)");
await expect(questionSelector.nth(1)).toHaveCSS("border-top-color", "rgb(204, 204, 204)");
await expect(questionSelector.nth(1)).toHaveCSS("border-top-style", "solid");
await expect(questionSelector.nth(1)).toHaveCSS("border-top-width", "1px");
});

if (framework === "angular" || framework === "react") {
test.skip("Check that survey calls afterRender if model changed", async ({ page }) => {
await page.evaluate(() => {
window["model2"] = new window["Survey"].Model({});
window.setSurvey(window["model1"]);
});
expect(await checkResizeObserverExists(page, "model1")).toBeTruthy();

await page.evaluate(() => {
window["model2"] = new window["Survey"].Model({});
window.setSurvey(window["model2"]);
});
expect(await checkResizeObserverExists(page, "model1")).toBeFalsy();
expect(await checkResizeObserverExists(page, "model2")).toBeTruthy();
});
}
});
});
206 changes: 206 additions & 0 deletions e2e/survey/autoNextPage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import { test, expect } from "@playwright/test";
import { frameworks, url, initSurvey, getSurveyResult } from "../helper";

const title = "autoNextPage";

const json = {
focusFirstQuestionAutomatic: true,
title: "American History",
showProgressBar: "bottom",
goNextPageAutomatic: true,
pages: [
{
elements: [
{
type: "radiogroup",
name: "civilwar",
title: "When was the Civil War?",
choices: [
"1750-1800",
"1800-1850",
"1850-1900",
"1900-1950",
"after 1950"
]
}
]
},
{
elements: [
{
type: "radiogroup",
name: "libertyordeath",
title: "Who said 'Give me liberty or give me death?'",
choices: [
"John Hancock",
"James Madison",
"Patrick Henry",
"Samuel Adams"
]
}
]
},
{
elements: [
{
type: "radiogroup",
name: "magnacarta",
title: "What is the Magna Carta?",
choices: [
"The foundation of the British parliamentary system",
"The Great Seal of the monarchs of England",
"The French Declaration of the Rights of Man",
"The charter signed by the Pilgrims on the Mayflower"
]
}
]
}
],
completedHtml:
"<p>Your anwers are:</p><p>When was the Civil War?: <b>{civilwar}</b>. The correct is: <b>1850-1900</b></p><p>Who said 'Give me liberty or give me death?': <b>{libertyordeath}</b>. The correct is: <b>Patrick Henry</b></p><p>What is the Magna Carta?: <b>{magnacarta}</b>. The correct is: <b>The foundation of the British parliamentary system</b></p>"
};

const json2 = {
focusFirstQuestionAutomatic: true,
goNextPageAutomatic: true,
pages: [
{
elements: [
{
type: "matrix",
name: "q1",
columns: [1, 2, 3],
rows: ["A", "B", "C"]
}
]
}
]
};

const json3 = {
focusFirstQuestionAutomatic: true,
goNextPageAutomatic: true,
pages: [
{
elements: [
{
type: "rating",
name: "q1"
}
]
}
]
};

frameworks.forEach((framework) => {
test.describe(`${framework} ${title}`, () => {
test.beforeEach(async ({ page }) => {
await page.goto(`${url}${framework}`);
});

test("check auto next page", async ({ page }) => {
await initSurvey(page, framework, json);
const getProgressTextPosition = async (index: number) => {
const content = await page.content();
return content.indexOf(`Page ${index} of 3`);
};
const firstRadioElement = page.locator(".sd-radio__decorator").first();

expect(await getProgressTextPosition(1)).not.toBe(-1);
await firstRadioElement.click();
await page.waitForTimeout(500);
expect(await getProgressTextPosition(2)).not.toBe(-1);
await firstRadioElement.click();
await page.waitForTimeout(500);
expect(await getProgressTextPosition(3)).not.toBe(-1);
await firstRadioElement.click();
await page.waitForTimeout(500);

const surveyResult = await getSurveyResult(page);
expect(surveyResult).toEqual({
civilwar: "1750-1800",
libertyordeath: "John Hancock",
magnacarta: "The foundation of the British parliamentary system"
});
});

test("check auto next page with keyboard", async ({ page }) => {
await initSurvey(page, framework, json);
const getProgressTextPosition = async (index: number) => {
const content = await page.content();
return content.indexOf(`Page ${index} of 3`);
};

expect(await getProgressTextPosition(1)).not.toBe(-1);
await page.keyboard.press("ArrowDown");
await page.keyboard.press("Tab");
await page.keyboard.press("Enter");
expect(await getProgressTextPosition(2)).not.toBe(-1);
await page.keyboard.press("ArrowDown");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Enter");
expect(await getProgressTextPosition(3)).not.toBe(-1);
await page.keyboard.press("ArrowDown");
await page.keyboard.press("Tab");
await page.keyboard.press("Tab");
await page.keyboard.press("Enter");

const surveyResult = await getSurveyResult(page);
expect(surveyResult).toEqual({
civilwar: "1800-1850",
libertyordeath: "James Madison",
magnacarta: "The Great Seal of the monarchs of England"
});
});

test("check auto next page with matrix", async ({ page }) => {
await initSurvey(page, framework, json2);
await page.locator("tr").filter({ hasText: "A" }).locator("span").nth(1).click();
await page.waitForTimeout(500);
await page.locator("tr").filter({ hasText: "B" }).locator("span").nth(2).click();
await page.waitForTimeout(500);
await page.locator("tr").filter({ hasText: "C" }).locator("span").nth(3).click();
await page.waitForTimeout(500);

const surveyResult = await getSurveyResult(page);
expect(surveyResult.q1).toEqual({ A: 1, B: 2, C: 3 });
});

test("check auto next page with matrix + keyboard", async ({ page }) => {
await initSurvey(page, framework, json2);
await page.keyboard.press("Space");
await page.keyboard.press("Tab");
await page.keyboard.press("ArrowRight");
await page.keyboard.press("Tab");
await page.keyboard.press("ArrowRight");
await page.keyboard.press("ArrowRight");
await page.keyboard.press("Tab");
await page.keyboard.press("Enter");

const surveyResult = await getSurveyResult(page);
expect(surveyResult.q1).toEqual({ A: 1, B: 2, C: 3 });
});

test("check auto next page with rating", async ({ page }) => {
await initSurvey(page, framework, json3);
const label3 = page.locator("label", { hasText: "3" });
await label3.click();
await page.waitForTimeout(500);

const surveyResult = await getSurveyResult(page);
expect(surveyResult.q1).toBe(3);
});

test("check auto next page with rating + keyboard", async ({ page }) => {
await initSurvey(page, framework, json3);
await page.keyboard.press("ArrowRight");
await page.keyboard.press("ArrowRight");
await page.keyboard.press("Tab");
await page.keyboard.press("Enter");

const surveyResult = await getSurveyResult(page);
expect(surveyResult.q1).toBe(3);
});
});
});
Loading