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, + }, + }; +}