diff --git a/package.json b/package.json
index da03365f6b1..5be0438e0fd 100644
--- a/package.json
+++ b/package.json
@@ -83,11 +83,11 @@
"build:test-tools": "npm run build -w @tools/test-tools",
"test": "jest --runInBand",
"test:unit": "jest --selectProjects=unit",
- "test:visualization": "playwright test -c ./packages/tools/tests/playwright.config.ts",
- "test:visualization:ui": "playwright test -c ./packages/tools/tests/playwright.config.ts --ui",
+ "test:visualization": "playwright test -c ./playwright.config.ts",
+ "test:visualization:ui": "playwright test -c ./playwright.config.ts --ui",
"test:integration": "jest --selectProjects=integration --runInBand && npm run test -w @tools/memory-leak-tests",
- "test:performance": "playwright test -c ./packages/tools/tests/playwright.config.ts --project=performance",
- "test:interactions": "playwright test -c ./packages/tools/tests/playwright.config.ts --project=interaction",
+ "test:performance": "playwright test -c ./playwright.config.ts --project=performance",
+ "test:interactions": "playwright test -c ./playwright.config.ts --project=interaction",
"test:escheck": "nx run-many --target=test:escheck --parallel --maxParallel=6",
"test:docs": "node ./scripts/typedoc-generator.js",
"prepare": "ts-patch install -s && npm run build:tools && npm i @dev/build-tools -D && npm run build:assets && npm run build:test-tools",
diff --git a/packages/tools/playground/public/index.html b/packages/tools/playground/public/index.html
index e168e8f2086..704965a550f 100644
--- a/packages/tools/playground/public/index.html
+++ b/packages/tools/playground/public/index.html
@@ -1,14 +1,16 @@
-
+
Babylon.js Playground
@@ -38,8 +40,8 @@
-
-
+
+
diff --git a/packages/tools/playground/test/interactions.playground.test.ts b/packages/tools/playground/test/interactions.playground.test.ts
new file mode 100644
index 00000000000..7002e12aed9
--- /dev/null
+++ b/packages/tools/playground/test/interactions.playground.test.ts
@@ -0,0 +1,80 @@
+import { test, expect } from "@playwright/test";
+
+test("Playground is loaded (Desktop)", async ({ page }) => {
+ await page.goto("https://playground.babylonjs.com/", {
+ waitUntil: "networkidle",
+ });
+ page.setViewportSize({
+ width: 1920,
+ height: 1080,
+ });
+ // check visibility of both canvas AND the editor
+ expect(page.locator("#canvasZone")).toBeVisible();
+ expect(page.locator("#monacoHost")).toBeVisible();
+ expect(page.locator("#pg-header")).toBeVisible();
+});
+
+test("Playground is loaded (Mobile)", async ({ page }) => {
+ await page.goto("https://playground.babylonjs.com/", {
+ waitUntil: "networkidle",
+ });
+ page.setViewportSize({
+ width: 800,
+ height: 1080,
+ });
+ // check visibility of both canvas AND the editor
+ expect(page.locator("#canvasZone")).toBeVisible();
+ expect(page.locator("#monacoHost")).not.toBeVisible();
+ expect(page.locator(".hamburger-button")).toBeVisible();
+
+ // click the "Switch to code" link
+ await page.getByTitle("Switch to code").click();
+ expect(page.locator("#canvasZone")).not.toBeVisible();
+ expect(page.locator("#monacoHost")).toBeVisible();
+});
+
+test("Examples can be loaded", async ({ page }) => {
+ await page.goto("https://playground.babylonjs.com/", {
+ waitUntil: "networkidle",
+ });
+ page.setViewportSize({
+ width: 1920,
+ height: 1080,
+ });
+
+ // click the "Examples" button
+ await page.getByTitle("Examples").click();
+
+ expect(page.locator("#examples")).toBeVisible();
+
+ await page.locator(".example").nth(3).click();
+
+ expect(page.url()).toContain("#7V0Y1I#2");
+});
+
+test("User can interact with the playground", async ({ page }) => {
+ await page.goto("https://playground.babylonjs.com/", {
+ waitUntil: "networkidle",
+ });
+ page.setViewportSize({
+ width: 1920,
+ height: 1080,
+ });
+
+ await page.locator(".view-lines > div:nth-child(16)").click();
+ await page.keyboard.type("camera", { delay: 50 });
+ expect(page.locator(".editor-widget")).toBeVisible();
+ await page.waitForTimeout(100);
+ await page.getByLabel("camera", { exact: true }).locator("span").filter({ hasText: "camera" }).first().click();
+
+ // change light's intensity to 0.2
+ await page.getByText("0.7").click();
+ await page.keyboard.press("ArrowRight");
+ await page.keyboard.press("ArrowRight");
+ await page.keyboard.press("Backspace");
+ await page.keyboard.press("2");
+
+ await page.getByTitle("Run\nAlt+Enter").getByRole("img").click();
+
+ await expect(page.locator("#canvasZone")).toHaveScreenshot();
+});
diff --git a/packages/tools/tests/browserstack.config.ts b/packages/tools/tests/browserstack.config.ts
index 0a4c91f3a60..4b4e1925f01 100644
--- a/packages/tools/tests/browserstack.config.ts
+++ b/packages/tools/tests/browserstack.config.ts
@@ -24,7 +24,7 @@ export const BS_LOCAL_ARGS = {
export const bsLocal = new BrowserStackLocal.Local();
// Patching the capabilities dynamically according to the project name.
-const patchCaps = (name, title) => {
+const patchCaps = (name: string, title: string) => {
let combination = name.split(/@browserstack/)[0];
let [browerCaps, osCaps] = combination.split(/:/);
let [browser, browser_version] = browerCaps.split(/@/);
@@ -43,4 +43,3 @@ export const getCdpEndpoint = (name: string, title: string) => {
const cdpUrl = `wss://cdp.browserstack.com/playwright?caps=${encodeURIComponent(JSON.stringify(caps))}`;
return cdpUrl;
};
-
diff --git a/packages/tools/tests/package.json b/packages/tools/tests/package.json
index 9c1d9a4bd03..a5d009932c6 100644
--- a/packages/tools/tests/package.json
+++ b/packages/tools/tests/package.json
@@ -16,7 +16,7 @@
"build": "node ./build.js",
"analyse": "webpack --profile --json > stats.json",
"generate-file-size-report": "node ./scripts/generateFileSizes.js",
- "test:playwright": "playwright test"
+ "test:playwright": "playwright test --config ../../../playwright.config.ts"
},
"devDependencies": {
"@dev/core": "^1.0.0",
diff --git a/packages/tools/tests/playwright.config.ts b/packages/tools/tests/playwright.config.ts
deleted file mode 100644
index 50faea0aa3a..00000000000
--- a/packages/tools/tests/playwright.config.ts
+++ /dev/null
@@ -1,143 +0,0 @@
-import { defineConfig, devices } from "@playwright/test";
-import { getCdpEndpoint } from "./browserstack.config";
-
-import { populateEnvironment } from "@dev/build-tools";
-populateEnvironment();
-
-const isCI = !!process.env.CI;
-const browserType = process.env.BROWSER || (isCI ? "Firefox" : "Chrome");
-const numberOfWorkers = process.env.CIWORKERS ? +process.env.CIWORKERS : process.env.CI ? 1 : browserType === "BrowserStack" ? 1 : undefined;
-const customFlags = process.env.CUSTOM_FLAGS ? process.env.CUSTOM_FLAGS.split(" ") : [];
-const headless = process.env.HEADLESS !== "false";
-const forceChrome = process.env.FORCE_CHROME === "true";
-
-const args = browserType === "Chrome" ? ["--use-angle=default", "--js-flags=--expose-gc"] : ["-wait-for-browser"];
-args.push(...customFlags);
-
-const browserStackBrowser = process.env.BROWSERSTACK_BROWSER || "chrome@latest:OSX Sonoma";
-
-export default defineConfig({
- testDir: "./test/playwright",
- /* Run tests in files in parallel */
- fullyParallel: true,
- /* Fail the build on CI if you accidentally left test.only in the source code. */
- forbidOnly: !!process.env.CI,
- /* Retry on CI only */
- retries: process.env.CI ? 2 : 1,
- /* Opt out of parallel tests on CI. */
- workers: numberOfWorkers,
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
- reporter: process.env.CI ? [["line"], ["junit", { outputFile: "junit.xml" }], ["html", { open: "never" }]] : [["list"], ["html"]],
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
- use: {
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: "on-first-retry",
- ignoreHTTPSErrors: true,
- },
-
- globalSetup: browserType === "BrowserStack" ? require.resolve("./globalSetup.ts") : undefined,
- globalTeardown: browserType === "BrowserStack" ? require.resolve("./globalTeardown.ts") : undefined,
-
- /* Project configuration */
- projects: [
- {
- name: "webgl2",
- testMatch: "**/*webgl2.test.ts",
- use: forceChrome
- ? {
- // use real chrome (not chromium) for webgpu tests
- channel: "chrome",
- headless,
- launchOptions: {
- args,
- },
- }
- : browserType === "BrowserStack"
- ? {
- connectOptions: { wsEndpoint: getCdpEndpoint(browserStackBrowser, "WebGL2") },
- }
- : {
- ...devices["Desktop " + browserType],
- headless,
- launchOptions: {
- args,
- },
- },
- },
- {
- name: "webgl1",
- testMatch: "**/*webgl1.test.ts",
- use: forceChrome
- ? {
- // use real chrome (not chromium) for webgpu tests
- channel: "chrome",
- headless,
- launchOptions: {
- args,
- },
- }
- : browserType === "BrowserStack"
- ? {
- connectOptions: { wsEndpoint: getCdpEndpoint(browserStackBrowser, "WebGL1") },
- }
- : {
- ...devices["Desktop " + browserType],
- headless,
- launchOptions: {
- args,
- },
- },
- },
- {
- name: "webgpu",
- testMatch: "**/*webgpu.test.ts",
- use:
- browserType === "BrowserStack"
- ? {
- connectOptions: { wsEndpoint: getCdpEndpoint(browserStackBrowser, "WebGPU") },
- }
- : {
- // use real chrome (not chromium) for webgpu tests
- channel: "chrome",
- headless,
- launchOptions: {
- args,
- },
- },
- },
- {
- name: "interaction",
- testMatch: "**/interaction.test.ts",
- use: {
- ...devices["Desktop Safari"],
- headless,
- },
- },
- {
- name: "performance",
- testMatch: "**/performance.test.ts",
- use: forceChrome
- ? {
- // use real chrome (not chromium) for webgpu tests
- channel: "chrome",
- headless,
- launchOptions: {
- args,
- },
- }
- : browserType === "BrowserStack"
- ? {
- connectOptions: { wsEndpoint: getCdpEndpoint(browserStackBrowser, "WebGL2") },
- }
- : {
- ...devices["Desktop " + browserType],
- headless,
- launchOptions: {
- args,
- },
- },
- },
- ],
-
- snapshotPathTemplate: "test/visualization/ReferenceImages/{arg}{ext}",
-});
diff --git a/packages/tools/tests/test/playwright/performance.test.ts b/packages/tools/tests/test/playwright/performance.test.ts
index c4b090e3339..ecb8b12481d 100644
--- a/packages/tools/tests/test/playwright/performance.test.ts
+++ b/packages/tools/tests/test/playwright/performance.test.ts
@@ -37,9 +37,9 @@ export const checkPerformanceOfScene = async (page: Page, baseUrl: string, numbe
export const evaluateRenderScene = async ({ renderCount }: { renderCount: number }): Promise => {
window.BABYLON.SceneLoader.ShowLoadingScreen = false;
- window.scene.useConstantAnimationDeltaTime = true;
+ (window.scene as any).useConstantAnimationDeltaTime = true;
- await window.scene.whenReadyAsync();
+ await (window.scene as any).whenReadyAsync();
if (window.scene && window.engine) {
const now = performance.now();
@@ -202,4 +202,3 @@ export const performanceTests = async (engineType = "webgl2", testFileName = "co
};
performanceTests("webgl2", "config", false, false, true, false);
-
diff --git a/packages/tools/tests/test/visualization/ReferenceImages/User-can-interact-with-the-playground-1.png b/packages/tools/tests/test/visualization/ReferenceImages/User-can-interact-with-the-playground-1.png
new file mode 100644
index 00000000000..fc47bddef83
Binary files /dev/null and b/packages/tools/tests/test/visualization/ReferenceImages/User-can-interact-with-the-playground-1.png differ
diff --git a/packages/tools/tests/test/visualization/visualization.webgl2.test.ts b/packages/tools/tests/test/visualization/visualization.webgl2.test.ts
deleted file mode 100644
index 19718369394..00000000000
--- a/packages/tools/tests/test/visualization/visualization.webgl2.test.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { evaluateTests } from "./visualization.utils";
-
-evaluateTests("webgl2", "config", false, false, true, false);
diff --git a/packages/tools/tests/test/visualization/visualization.webgpu.test.ts b/packages/tools/tests/test/visualization/visualization.webgpu.test.ts
deleted file mode 100644
index 6a255fbe428..00000000000
--- a/packages/tools/tests/test/visualization/visualization.webgpu.test.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { evaluateTests } from "./visualization.utils";
-
-evaluateTests("webgpu", "webgpu", true, false, false, true);
diff --git a/packages/tools/tests/test/visualization/webgpu.json b/packages/tools/tests/test/visualization/webgpu.json
deleted file mode 100644
index 1f1a54eb7be..00000000000
--- a/packages/tools/tests/test/visualization/webgpu.json
+++ /dev/null
@@ -1,182 +0,0 @@
-{
- "root": "https://cdn.babylonjs.com",
- "tests": [
- {
- "title": "edge-renderer-and-zOffset",
- "renderCount": 5,
- "playgroundId": "#3DBA8X#1"
- },
- {
- "title": "cube-with-holes-using-stencil-buffer",
- "playgroundId": "#CW5PRI#11"
- },
- {
- "title": "water-material",
- "playgroundId": "#EUH2VL#1"
- },
- {
- "title": "show-bounding-box",
- "renderCount": 5,
- "playgroundId": "#0LN1JD#0"
- },
- {
- "title": "cube-reflection-with-probe-and-mirrors",
- "renderCount": 20,
- "playgroundId": "#X3V1NN#7"
- },
- {
- "title": "sphere-with-custom-shader-to-display-wireframe-using-glow-layer",
- "renderCount": 5,
- "playgroundId": "#Y05E2C#6"
- },
- {
- "title": "blur-cube-with-the-effect-renderer",
- "renderCount": 20,
- "playgroundId": "#4C900K#2"
- },
- {
- "title": "simple-render-target-with-blue-spheres",
- "playgroundId": "#NRR7F4#0"
- },
- {
- "title": "neon-pipe-with-glow-layer",
- "renderCount": 5,
- "playgroundId": "#X229PI#0"
- },
- {
- "title": "pillars-sphere-and-torus-with-PCSS-shadows",
- "playgroundId": "#WL4Q8J#0",
- "excludedEngines": ["webgl1"]
- },
- {
- "title": "soft-transparent-shadows",
- "playgroundId": "#G3DJGA#0",
- "excludedEngines": ["webgl1"]
- },
- {
- "title": "default-render-pipeline",
- "playgroundId": "#GAFR36#0",
- "renderCount": 5
- },
- {
- "title": "torus-knot-mirror",
- "playgroundId": "#M5GFLR#0"
- },
- {
- "title": "simple-sphere-in-4-mirrors",
- "playgroundId": "#58CFTW#4"
- },
- {
- "title": "procedural-texture-with-node-material",
- "renderCount": 10,
- "playgroundId": "#IA4X0H#1"
- },
- {
- "title": "apply-all-post-processes",
- "renderCount": 10,
- "playgroundId": "#MJ59Y8#2"
- },
- {
- "title": "simple-custom-shader",
- "renderCount": 5,
- "playgroundId": "#6GFJNR#2"
- },
- {
- "title": "show-multiple-guis",
- "renderCount": 5,
- "playgroundId": "#6X9UMD#12"
- },
- {
- "title": "skybox-with-boombox",
- "renderCount": 20,
- "playgroundId": "#I2TR8G#0"
- },
- {
- "title": "show-all-procedural-textures",
- "renderCount": 5,
- "playgroundId": "#4N0QRP#1"
- },
- {
- "title": "custom-handling-of-materials-for-render-target-pass",
- "renderCount": 60,
- "playgroundId": "#FIVL25#21"
- },
- {
- "title": "dissolve-effect-with-node-material-and-glow-layer",
- "renderCount": 2,
- "playgroundId": "#F6PGMC"
- },
- {
- "title": "cascaded-shadow-maps-and-flying-saucers",
- "renderCount": 10,
- "playgroundId": "#IIZ9UU#63",
- "excludedEngines": ["webgl1"]
- },
- {
- "title": "halo-particle-system",
- "renderCount": 20,
- "playgroundId": "#2441BU#1"
- },
- {
- "title": "depth-renderer",
- "renderCount": 5,
- "playgroundId": "#1PHYB0#112"
- },
- {
- "title": "particle-system-with-custom-nme-shader",
- "renderCount": 5,
- "playgroundId": "#DMLLV2"
- },
- {
- "title": "create-environment-texture",
- "playgroundId": "#L4RXKN#10",
- "excludedEngines": ["webgl1"]
- },
- {
- "title": "particle-system-matrix-like",
- "renderCount": 100,
- "playgroundId": "#WL44T7#1"
- },
- {
- "title": "lens-flare",
- "playgroundId": "#KICG93"
- },
- {
- "title": "update-sampler-info",
- "renderCount": 5,
- "playgroundId": "#7GKK8E#20"
- },
- {
- "title": "wgsl-in-shadermaterial",
- "renderCount": 30,
- "playgroundId": "#8RU8Q3#157",
- "excludedEngines": ["webgl1", "webgl2"]
- },
- {
- "title": "terrain-erosion",
- "renderCount": 15,
- "playgroundId": "#C90R62#17",
- "excludedEngines": ["webgl1", "webgl2"]
- },
- {
- "title": "change-texture-of-material",
- "renderCount": 10,
- "playgroundId": "#7PN9PH#2"
- },
- {
- "title": "screen-space-curvature",
- "renderCount": 5,
- "playgroundId": "#YF8D42#22"
- },
- {
- "title": "digital-rain",
- "renderCount": 8,
- "playgroundId": "#2I28SC#36"
- },
- {
- "title": "ascii-art",
- "renderCount": 10,
- "playgroundId": "#2I28SC#25"
- }
- ]
-}
diff --git a/playwright.config.ts b/playwright.config.ts
new file mode 100644
index 00000000000..59fe31c5d98
--- /dev/null
+++ b/playwright.config.ts
@@ -0,0 +1,125 @@
+import { defineConfig, devices } from "@playwright/test";
+import { populateEnvironment } from "@dev/build-tools";
+import { getCdpEndpoint } from "./packages/tools/tests/browserstack.config";
+populateEnvironment();
+
+const isCI = !!process.env.CI;
+const browserType = process.env.BROWSER || (isCI ? "Firefox" : "Chrome");
+const numberOfWorkers = process.env.CIWORKERS ? +process.env.CIWORKERS : process.env.CI ? 1 : browserType === "BrowserStack" ? 1 : undefined;
+const customFlags = process.env.CUSTOM_FLAGS ? process.env.CUSTOM_FLAGS.split(" ") : [];
+const headless = process.env.HEADLESS !== "false";
+const forceChrome = process.env.FORCE_CHROME === "true";
+
+const browserStackBrowser = process.env.BROWSERSTACK_BROWSER || "chrome@latest:OSX Sonoma";
+
+export default defineConfig({
+ // testDir: "./test/playwright",
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 1,
+ /* Opt out of parallel tests on CI. */
+ workers: numberOfWorkers,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: process.env.CI ? [["line"], ["junit", { outputFile: "junit.xml" }], ["html", { open: "never" }]] : [["list"], ["html"]],
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: "on-first-retry",
+ ignoreHTTPSErrors: true,
+ },
+
+ globalSetup: browserType === "BrowserStack" ? require.resolve("./packages/tools/tests/globalSetup.ts") : undefined,
+ globalTeardown: browserType === "BrowserStack" ? require.resolve("./packages/tools/tests/globalTeardown.ts") : undefined,
+
+ /* Project configuration */
+ projects: [
+ {
+ name: "webgl2",
+ testMatch: "**/*webgl2.test.ts",
+ use: getUseDefinition("WebGL2"),
+ },
+ // {
+ // name: "webgl1",
+ // testMatch: "**/*webgl1.test.ts",
+ // use: forceChrome
+ // ? {
+ // // use real chrome (not chromium) for webgpu tests
+ // channel: "chrome",
+ // headless,
+ // launchOptions: {
+ // args,
+ // },
+ // }
+ // : browserType === "BrowserStack"
+ // ? {
+ // connectOptions: { wsEndpoint: getCdpEndpoint(browserStackBrowser, "WebGL1") },
+ // }
+ // : {
+ // ...devices["Desktop " + browserType],
+ // headless,
+ // launchOptions: {
+ // args,
+ // },
+ // },
+ // },
+ {
+ name: "webgpu",
+ testMatch: "**/*webgpu.test.ts",
+ use: getUseDefinition("WebGPU"),
+ },
+ {
+ name: "interaction",
+ testMatch: "**/interaction.test.ts",
+ use: getUseDefinition("Interaction", "Safari", true),
+ },
+ {
+ name: "performance",
+ testMatch: "**/performance.test.ts",
+ use: getUseDefinition("Performance"),
+ },
+ {
+ name: "playground",
+ testMatch: "**/*.playground.test.ts",
+ use: getUseDefinition("Playground"),
+ },
+ ],
+
+ snapshotPathTemplate: "packages/tools/tests/test/visualization/ReferenceImages/{arg}{ext}",
+});
+
+function getUseDefinition(title: string, browser = browserType, noBrowserStack = false) {
+ const args = browser === "Chrome" ? ["--use-angle=default", "--js-flags=--expose-gc"] : browser === "Firefox" ? ["-wait-for-browser"] : [];
+ args.push(...customFlags);
+ if (noBrowserStack) {
+ return {
+ ...devices["Desktop " + browser],
+ headless,
+ launchOptions: {
+ args,
+ },
+ };
+ }
+ return forceChrome
+ ? {
+ // use real chrome (not chromium) for webgpu tests
+ channel: "chrome",
+ headless,
+ launchOptions: {
+ args,
+ },
+ }
+ : browserType === "BrowserStack"
+ ? {
+ connectOptions: { wsEndpoint: getCdpEndpoint(browserStackBrowser, title) },
+ }
+ : {
+ ...devices["Desktop " + browser],
+ headless,
+ launchOptions: {
+ args,
+ },
+ };
+}