mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-12 12:40:29 +08:00
Slider browser unit tests (#4681)
* First commit * Fix test * move to .config * indent * Upgrade pnpm * Lint + ts * Add more tests * Lint * fix test * Use spy
This commit is contained in:
parent
b7a52c410a
commit
340718e6c2
93
.config/basevite.config.ts
Normal file
93
.config/basevite.config.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||
import sveltePreprocess from "svelte-preprocess";
|
||||
// @ts-ignore
|
||||
import custom_media from "postcss-custom-media";
|
||||
import global_data from "@csstools/postcss-global-data";
|
||||
// @ts-ignore
|
||||
import prefixer from "postcss-prefix-selector";
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
||||
const version_path = join(__dirname, "..", "gradio", "version.txt");
|
||||
const theme_token_path = join(
|
||||
__dirname,
|
||||
"..",
|
||||
"js",
|
||||
"theme",
|
||||
"src",
|
||||
"tokens.css"
|
||||
);
|
||||
|
||||
const version = readFileSync(version_path, { encoding: "utf-8" })
|
||||
.trim()
|
||||
.replace(/\./g, "-");
|
||||
|
||||
//@ts-ignore
|
||||
export default defineConfig(({ mode }) => {
|
||||
const production =
|
||||
mode === "production:cdn" ||
|
||||
mode === "production:local" ||
|
||||
mode === "production:website";
|
||||
|
||||
return {
|
||||
server: {
|
||||
port: 9876
|
||||
},
|
||||
|
||||
build: {
|
||||
sourcemap: false,
|
||||
target: "esnext",
|
||||
minify: production
|
||||
},
|
||||
define: {
|
||||
BUILD_MODE: production ? JSON.stringify("prod") : JSON.stringify("dev"),
|
||||
BACKEND_URL: production
|
||||
? JSON.stringify("")
|
||||
: JSON.stringify("http://localhost:7860/"),
|
||||
GRADIO_VERSION: JSON.stringify(version)
|
||||
},
|
||||
css: {
|
||||
postcss: {
|
||||
plugins: [
|
||||
prefixer({
|
||||
prefix: `.gradio-container-${version}`,
|
||||
// @ts-ignore
|
||||
transform(prefix, selector, prefixedSelector, fileName) {
|
||||
if (selector.indexOf("gradio-container") > -1) {
|
||||
return prefix;
|
||||
} else if (
|
||||
selector.indexOf(":root") > -1 ||
|
||||
selector.indexOf("dark") > -1 ||
|
||||
fileName.indexOf(".svelte") > -1
|
||||
) {
|
||||
return selector;
|
||||
}
|
||||
return prefixedSelector;
|
||||
}
|
||||
}),
|
||||
custom_media()
|
||||
]
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
svelte({
|
||||
inspector: true,
|
||||
compilerOptions: {
|
||||
dev: !production
|
||||
},
|
||||
hot: !process.env.VITEST && !production,
|
||||
preprocess: sveltePreprocess({
|
||||
postcss: {
|
||||
plugins: [
|
||||
global_data({ files: [theme_token_path] }),
|
||||
custom_media()
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
]
|
||||
};
|
||||
});
|
41
.config/playwright-ct.config.ts
Normal file
41
.config/playwright-ct.config.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { defineConfig, devices } from "@playwright/experimental-ct-svelte";
|
||||
import config from "./basevite.config";
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
testDir: "../",
|
||||
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
|
||||
snapshotDir: "./__snapshots__",
|
||||
/* Maximum time one test can run for. */
|
||||
timeout: 10 * 1000,
|
||||
/* 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 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "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",
|
||||
|
||||
/* Port to use for Playwright component endpoint. */
|
||||
ctPort: 3100,
|
||||
ctViteConfig: config({ mode: "development" })
|
||||
},
|
||||
testMatch: "*.component.spec.ts",
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] }
|
||||
}
|
||||
]
|
||||
});
|
@ -12,7 +12,12 @@ const TEST_FILES_PATH = join(__dirname, "..", "js", "app", "test");
|
||||
const ROOT = join(__dirname, "..");
|
||||
|
||||
const test_files = readdirSync(TEST_FILES_PATH)
|
||||
.filter((f) => f.endsWith("spec.ts") && !f.endsWith(".skip.spec.ts"))
|
||||
.filter(
|
||||
(f) =>
|
||||
f.endsWith("spec.ts") &&
|
||||
!f.endsWith(".skip.spec.ts") &&
|
||||
!f.endsWith(".component.spec.ts")
|
||||
)
|
||||
.map((f) => basename(f, ".spec.ts"));
|
||||
|
||||
export default async function global_setup() {
|
||||
|
12
.config/playwright/index.html
Normal file
12
.config/playwright/index.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Testing Page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="./index.ts"></script>
|
||||
</body>
|
||||
</html>
|
2
.config/playwright/index.ts
Normal file
2
.config/playwright/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
// Import styles, initialize component theme here.
|
||||
// import '../src/common.css';
|
4
.github/workflows/ui.yml
vendored
4
.github/workflows/ui.yml
vendored
@ -53,3 +53,7 @@ jobs:
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
pnpm test:browser
|
||||
- name: run browser component tests
|
||||
run: |
|
||||
. venv/bin/activate
|
||||
pnpm run test:ct
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -29,6 +29,7 @@ tmp.zip
|
||||
coverage.xml
|
||||
test.txt
|
||||
**/snapshots/**/*.png
|
||||
playwright-report/
|
||||
|
||||
# Demos
|
||||
demo/tmp.zip
|
||||
@ -63,4 +64,7 @@ node_modules
|
||||
public/build/
|
||||
test-results
|
||||
client/js/test.js
|
||||
.config/test.py
|
||||
.config/test.py
|
||||
.config/playwright
|
||||
!.config/playwright/index.html
|
||||
!.config/playwright/index.ts
|
132
js/app/src/components/Slider/Slider.component.spec.ts
Normal file
132
js/app/src/components/Slider/Slider.component.spec.ts
Normal file
@ -0,0 +1,132 @@
|
||||
import { test, expect } from "@playwright/experimental-ct-svelte";
|
||||
import type { Page, Locator } from "@playwright/test";
|
||||
import Slider from "./Slider.svelte";
|
||||
import { spy } from "tinyspy";
|
||||
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
const loading_status: LoadingStatus = {
|
||||
eta: 0,
|
||||
queue_position: 1,
|
||||
queue_size: 1,
|
||||
status: "complete",
|
||||
scroll_to_output: false,
|
||||
visible: true,
|
||||
fn_index: 0,
|
||||
show_progress: "full"
|
||||
};
|
||||
|
||||
//taken from: https://github.com/microsoft/playwright/issues/20032
|
||||
async function changeSlider(
|
||||
page: Page,
|
||||
thumb: Locator,
|
||||
slider: Locator,
|
||||
targetPercentage: number
|
||||
) {
|
||||
const thumbBoundingBox = await thumb.boundingBox();
|
||||
const sliderBoundingBox = await slider.boundingBox();
|
||||
|
||||
if (thumbBoundingBox === null || sliderBoundingBox === null) {
|
||||
return; // NOTE it's probably better to throw an error here
|
||||
}
|
||||
|
||||
// Start from the middle of the slider's thumb
|
||||
const startPoint = {
|
||||
x: thumbBoundingBox.x + thumbBoundingBox.width / 2,
|
||||
y: thumbBoundingBox.y + thumbBoundingBox.height / 2
|
||||
};
|
||||
|
||||
// Slide it to some endpoint determined by the target percentage
|
||||
const endPoint = {
|
||||
x: sliderBoundingBox.x + sliderBoundingBox.width * targetPercentage,
|
||||
y: thumbBoundingBox.y + thumbBoundingBox.height / 2
|
||||
};
|
||||
|
||||
await page.mouse.move(startPoint.x, startPoint.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(endPoint.x, endPoint.y);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
test("Slider Default Value And Label rendered", async ({ mount }) => {
|
||||
const component = await mount(Slider, {
|
||||
props: {
|
||||
value: 3,
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
label: "My Slider",
|
||||
show_label: true,
|
||||
step: 1,
|
||||
mode: "dynamic",
|
||||
loading_status: loading_status
|
||||
}
|
||||
});
|
||||
await expect(component).toContainText("My Slider");
|
||||
await expect(component.getByLabel("My Slider")).toHaveValue("3");
|
||||
});
|
||||
|
||||
test("Slider respects show_label", async ({ mount, page }) => {
|
||||
const _ = await mount(Slider, {
|
||||
props: {
|
||||
value: 3,
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
label: "My Slider",
|
||||
show_label: false,
|
||||
step: 1,
|
||||
mode: "dynamic",
|
||||
loading_status: loading_status
|
||||
}
|
||||
});
|
||||
await expect(page.getByTestId("label")).toBeHidden();
|
||||
});
|
||||
|
||||
test("Slider Maximum/Minimum values", async ({ mount, page }) => {
|
||||
const component = await mount(Slider, {
|
||||
props: {
|
||||
value: 3,
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
label: "My Slider",
|
||||
show_label: true,
|
||||
step: 1,
|
||||
mode: "dynamic",
|
||||
loading_status: loading_status
|
||||
}
|
||||
});
|
||||
const slider = component.getByLabel("My Slider");
|
||||
await changeSlider(page, slider, slider, 1);
|
||||
await expect(component.getByLabel("My Slider")).toHaveValue("10");
|
||||
await changeSlider(page, slider, slider, 0);
|
||||
await expect(component.getByLabel("My Slider")).toHaveValue("0");
|
||||
});
|
||||
|
||||
test("Slider Change event", async ({ mount, page }) => {
|
||||
let change = spy();
|
||||
let release = spy();
|
||||
const component = await mount(Slider, {
|
||||
props: {
|
||||
value: 3,
|
||||
minimum: 0,
|
||||
maximum: 10,
|
||||
label: "My Slider",
|
||||
show_label: true,
|
||||
step: 1,
|
||||
mode: "dynamic",
|
||||
loading_status: loading_status
|
||||
},
|
||||
on: {
|
||||
change: change,
|
||||
release: release
|
||||
}
|
||||
});
|
||||
|
||||
const slider = page.getByLabel("Slider");
|
||||
|
||||
await changeSlider(page, slider, slider, 0.7);
|
||||
await expect(component.getByLabel("My Slider")).toHaveValue("7");
|
||||
|
||||
// More than one change event and one release event.
|
||||
await expect(change.callCount).toBeGreaterThan(1);
|
||||
await expect(release.callCount).toEqual(1);
|
||||
});
|
@ -1,48 +0,0 @@
|
||||
import { Page, Locator } from "@playwright/test";
|
||||
import { test, expect } from "@gradio/tootils";
|
||||
|
||||
//taken from: https://github.com/microsoft/playwright/issues/20032
|
||||
async function changeSlider(
|
||||
page: Page,
|
||||
thumb: Locator,
|
||||
slider: Locator,
|
||||
targetPercentage: number
|
||||
) {
|
||||
const thumbBoundingBox = await thumb.boundingBox();
|
||||
const sliderBoundingBox = await slider.boundingBox();
|
||||
|
||||
if (thumbBoundingBox === null || sliderBoundingBox === null) {
|
||||
return; // NOTE it's probably better to throw an error here
|
||||
}
|
||||
|
||||
// Start from the middle of the slider's thumb
|
||||
const startPoint = {
|
||||
x: thumbBoundingBox.x + thumbBoundingBox.width / 2,
|
||||
y: thumbBoundingBox.y + thumbBoundingBox.height / 2
|
||||
};
|
||||
|
||||
// Slide it to some endpoint determined by the target percentage
|
||||
const endPoint = {
|
||||
x: sliderBoundingBox.x + sliderBoundingBox.width * targetPercentage,
|
||||
y: thumbBoundingBox.y + thumbBoundingBox.height / 2
|
||||
};
|
||||
|
||||
await page.mouse.move(startPoint.x, startPoint.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(endPoint.x, endPoint.y);
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
test("slider release", async ({ page }) => {
|
||||
const slider = page.getByLabel("Slider");
|
||||
|
||||
await changeSlider(page, slider, slider, 0.7);
|
||||
|
||||
const value = page.getByLabel("On release");
|
||||
const events = page.getByLabel("Number of events fired");
|
||||
|
||||
const val = await slider.inputValue();
|
||||
expect(parseInt(val)).toBeCloseTo(70);
|
||||
expect(parseInt(await value.inputValue())).toBeCloseTo(70);
|
||||
expect(events).toHaveValue("1");
|
||||
});
|
@ -24,7 +24,8 @@
|
||||
"test:browser:verbose": "GRADIO_TEST_VERBOSE=true pnpm test:browser",
|
||||
"test:browser:debug": "pnpm --filter @gradio/app test:browser:debug",
|
||||
"ci:publish": "pnpm publish --no-git-checks --access public -r",
|
||||
"ci:version": "changeset version && pnpm i --lockfile-only"
|
||||
"ci:version": "changeset version && pnpm i --lockfile-only",
|
||||
"test:ct": "playwright test -c ./.config/playwright-ct.config.ts"
|
||||
},
|
||||
"type": "module",
|
||||
"author": "",
|
||||
@ -35,7 +36,7 @@
|
||||
"@changesets/cli": "^2.26.1",
|
||||
"@csstools/postcss-global-data": "^1.0.3",
|
||||
"@gradio/tootils": "workspace:^0.0.1",
|
||||
"@playwright/test": "^1.35.1",
|
||||
"@playwright/experimental-ct-svelte": "^1.35.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^2.0.0",
|
||||
"@tailwindcss/forms": "^0.5.0",
|
||||
"@testing-library/dom": "^9.0.0",
|
||||
@ -56,7 +57,6 @@
|
||||
"msw": "^1.0.0",
|
||||
"node-html-parser": "^6.0.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"playwright": "^1.35.1",
|
||||
"plotly.js-dist-min": "^2.10.1",
|
||||
"polka": "^1.0.0-next.22",
|
||||
"pollen-css": "^4.6.1",
|
||||
@ -80,6 +80,7 @@
|
||||
"vitest": "^0.32.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.35.1",
|
||||
"@types/three": "^0.152.0"
|
||||
},
|
||||
"prettier": {
|
||||
|
7308
pnpm-lock.yaml
generated
7308
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,10 @@
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"module": "es2020",
|
||||
"lib": ["es2020", "DOM"],
|
||||
"lib": [
|
||||
"es2020",
|
||||
"DOM"
|
||||
],
|
||||
"target": "es2020",
|
||||
/**
|
||||
svelte-preprocess cannot figure out whether you have a value or a type, so tell TypeScript
|
||||
@ -24,7 +27,7 @@
|
||||
"exclude": [
|
||||
"**/dist/**/*",
|
||||
"**/public/**/*",
|
||||
"**/.config/*",
|
||||
"**/.config/**/*",
|
||||
"**/*.test.ts",
|
||||
"**/dist",
|
||||
".github/**/*",
|
||||
@ -46,4 +49,4 @@
|
||||
"**/*.svelte",
|
||||
"client/js/**/*"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user