Remove mocks (#4550)

* changes

* changes

* remove mocks

* fix scripts

* tweak port

* add logs

* add logs

* do tests again

* tweaks

* fixes

* regen notebooks

* change workers

* change workers

* try to speed up ci

* try again

* try again

* try again

* try again

* try again

* fix actions

* again

* again

* again

* again

* again

* again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* try again

* add names to frontend ci steps
This commit is contained in:
pngwn 2023-06-19 21:02:03 +01:00 committed by GitHub
parent 309baab7f6
commit d6b6c87c4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 290 additions and 420 deletions

View File

@ -1,21 +1,102 @@
import polka from "polka";
import sirv from "sirv";
import path from "path";
import { dirname } from "path";
import { spawn, spawnSync } from "node:child_process";
import { join, basename } from "path";
import { fileURLToPath } from "url";
import { readdirSync, writeFileSync } from "fs";
const __dirname = dirname(fileURLToPath(import.meta.url));
const template = path.join(__dirname, "..", "gradio", "templates", "frontend");
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const TEST_APP_PATH = join(__dirname, "./test.py");
const TEST_FILES_PATH = join(__dirname, "..", "js", "app", "test");
const DEMO_MODULE_PATH = join(__dirname, "..", "demo", "__init__.py");
const ROOT = join(__dirname, "..");
const test_files = readdirSync(TEST_FILES_PATH)
.filter((f) => f.endsWith("spec.ts") && !f.endsWith(".skip.spec.ts"))
.map((f) => basename(f, ".spec.ts"));
export default async function global_setup() {
const serve = sirv(template);
const app = polka()
.use(serve)
.listen("9876", () => {
console.log(`> Running on localhost: 9876`);
});
const verbose = process.env.GRADIO_TEST_VERBOSE;
console.info("\nCreating test gradio app and starting server.\n");
const test_app = make_app(test_files);
writeFileSync(TEST_APP_PATH, test_app);
const app = await spawn_gradio_app(TEST_APP_PATH, verbose);
console.info("Server started. Running tests.\n");
return () => {
app.server.close();
console.log("\nTests complete, cleaning up server.\n");
kill_process(app);
};
}
const PORT_RE = new RegExp(`:7879`);
function spawn_gradio_app(app, verbose) {
return new Promise((res, rej) => {
const _process = spawn(`python`, [app], {
shell: true,
stdio: "pipe",
cwd: ROOT,
env: {
...process.env,
GRADIO_SERVER_PORT: `7879`,
PYTHONUNBUFFERED: "true"
}
});
_process.stdout.setEncoding("utf8");
_process.stdout.on("data", (data) => {
const _data = data.toString();
if (verbose) {
console.log("\n");
console.log("OUT: ", _data);
console.log("\n");
}
if (PORT_RE.test(_data)) {
res(_process);
}
});
_process.stderr.on("data", (data) => {
const _data = data.toString();
if (PORT_RE.test(_data)) {
res(_process);
}
if (verbose) {
console.warn("ERR: ", _data);
}
if (_data.includes("Traceback")) {
kill_process(_process);
throw new Error(
"Something went wrong in the python process. Enable verbose mode to see the stdout/err or the python child process."
);
rej();
}
});
});
}
function kill_process(process) {
return new Promise((res, rej) => {
process.on("close", res);
process.kill("SIGTERM");
});
}
function make_app(demos) {
return `import gradio as gr
import uvicorn
from fastapi import FastAPI
import gradio as gr
${demos.map((d) => `from demo.${d}.run import demo as ${d}`).join("\n")}
app = FastAPI()
${demos
.map((d) => `app = gr.mount_gradio_app(app, ${d}, path="/${d}")`)
.join("\n")}
config = uvicorn.Config(app, port=7879, log_level="info")
server = uvicorn.Server(config=config)
server.run()`;
}

View File

@ -5,6 +5,5 @@ export default {
},
// testMatch: /.*.spec.ts/,
testDir: "..",
globalSetup: "./playwright-setup.js",
workers: 1
globalSetup: "./playwright-setup.js"
};

View File

@ -0,0 +1,42 @@
name: 'install all deps'
description: 'Install all deps'
inputs:
always-install-pnpm:
description: 'Dictates whether or not we should install pnpm & dependencies, regardless of the cache'
default: false
runs:
using: "composite"
steps:
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: 3.8
cache: pip
cache-dependency-path: |
client/python/requirements.txt
requirements.txt
test/requirements.txt
- name: Create env
shell: bash
run: |
python -m pip install --upgrade virtualenv
python -m virtualenv venv
- uses: actions/cache@v3
id: cache
with:
path: |
venv/*
key: gradio-lib-ubuntu-latest-pip-${{ hashFiles('client/python/requirements.txt') }}-${{ hashFiles('requirements.txt') }}-${{ hashFiles('test/requirements.txt') }}
- name: Install Gradio (Linux)
shell: bash
run: |
. venv/bin/activate
python -m pip install -e .
- name: Install ffmpeg
uses: FedericoCarboni/setup-ffmpeg@v2
- name: install-frontend
uses: "./.github/actions/install-frontend-deps"
with:
always-install-pnpm: ${{ inputs.always-install-pnpm }}

View File

@ -0,0 +1,35 @@
name: 'install frontend'
description: 'Install frontend deps'
inputs:
always-install-pnpm:
description: 'Dictates whether or not we should install pnpm & dependencies, regardless of the cache'
default: false
runs:
using: "composite"
steps:
- uses: actions/cache@v3
id: frontend-cache
with:
path: |
gradio/templates/*
key: gradio-lib-front-end-${{ hashFiles('js/**')}}
- name: Install pnpm
if: steps.frontend-cache.outputs.cache-hit != 'true' || inputs.always-install-pnpm == 'true'
uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Install deps
if: steps.frontend-cache.outputs.cache-hit != 'true' || inputs.always-install-pnpm == 'true'
shell: bash
run: pnpm i --frozen-lockfile
- name: Build frontend
if: steps.frontend-cache.outputs.cache-hit != 'true'
shell: bash
run: pnpm build

View File

@ -21,20 +21,10 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: install dependencies
run: pnpm i --frozen-lockfile
- name: formatting check
run: pnpm format:check
- name: build css
run: pnpm css
uses: "./.github/actions/install-frontend-deps"
with:
always-install-pnpm: true
- name: build client
run: pnpm --filter @gradio/client build
- name: typecheck
@ -45,27 +35,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
- name: install dependencies
uses: "./.github/actions/install-all-deps"
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Install Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- run: pip install -e .
- run: pip install -r demo/outbreak_forecast/requirements.txt
- run: pnpm install --frozen-lockfile
always-install-pnpm: true
- name: install outbreak_forecast dependencies
run: |
. venv/bin/activate
python -m pip install -r demo/outbreak_forecast/requirements.txt
- run: pnpm exec playwright install chromium
- run: pnpm test:browser:full
- name: Upload failed tests screenshots
if: failure()
uses: actions/upload-artifact@v3
with:
retention-days: 3
name: test-failure-${{ github.run_id }}
path: js/app/test-results
- name: run browser tests
run: |
. venv/bin/activate
pnpm test:browser

3
.gitignore vendored
View File

@ -62,4 +62,5 @@ gradio/frpc_*
node_modules
public/build/
test-results
client/js/test.js
client/js/test.js
.config/test.py

View File

@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: blocks_xray"]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import random\n", "import time\n", "\n", "def xray_model(diseases, img):\n", " time.sleep(4)\n", " return [{disease: random.random() for disease in diseases}]\n", "\n", "\n", "def ct_model(diseases, img):\n", " time.sleep(3)\n", " return [{disease: 0.1 for disease in diseases}]\n", "\n", "with gr.Blocks() as demo:\n", " gr.Markdown(\n", " \"\"\"\n", "# Detect Disease From Scan\n", "With this model you can lorem ipsum\n", "- ipsum 1\n", "- ipsum 2\n", "\"\"\"\n", " )\n", " disease = gr.CheckboxGroup(\n", " info=\"Select the diseases you want to scan for.\",\n", " choices=[\"Covid\", \"Malaria\", \"Lung Cancer\"], label=\"Disease to Scan For\"\n", " )\n", " slider = gr.Slider(0, 100)\n", "\n", " with gr.Tab(\"X-ray\") as x_tab:\n", " with gr.Row():\n", " xray_scan = gr.Image()\n", " xray_results = gr.JSON()\n", " xray_run = gr.Button(\"Run\")\n", " xray_run.click(\n", " xray_model,\n", " inputs=[disease, xray_scan],\n", " outputs=xray_results,\n", " api_name=\"xray_model\"\n", " )\n", "\n", " with gr.Tab(\"CT Scan\"):\n", " with gr.Row():\n", " ct_scan = gr.Image()\n", " ct_results = gr.JSON()\n", " ct_run = gr.Button(\"Run\")\n", " ct_run.click(\n", " ct_model,\n", " inputs=[disease, ct_scan],\n", " outputs=ct_results,\n", " api_name=\"ct_model\"\n", " )\n", "\n", " upload_btn = gr.Button(\"Upload Results\", variant=\"primary\")\n", " upload_btn.click(\n", " lambda ct, xr: time.sleep(5),\n", " inputs=[ct_results, xray_results],\n", " outputs=[],\n", " )\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: blocks_xray"]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import time\n", "\n", "disease_values = [0.25, 0.5, 0.75]\n", "\n", "def xray_model(diseases, img):\n", " return [{disease: disease_values[idx] for idx,disease in enumerate(diseases)}]\n", "\n", "\n", "def ct_model(diseases, img):\n", " return [{disease: 0.1 for disease in diseases}]\n", "\n", "with gr.Blocks() as demo:\n", " gr.Markdown(\n", " \"\"\"\n", "# Detect Disease From Scan\n", "With this model you can lorem ipsum\n", "- ipsum 1\n", "- ipsum 2\n", "\"\"\"\n", " )\n", " disease = gr.CheckboxGroup(\n", " info=\"Select the diseases you want to scan for.\",\n", " choices=[\"Covid\", \"Malaria\", \"Lung Cancer\"], label=\"Disease to Scan For\"\n", " )\n", " slider = gr.Slider(0, 100)\n", "\n", " with gr.Tab(\"X-ray\") as x_tab:\n", " with gr.Row():\n", " xray_scan = gr.Image()\n", " xray_results = gr.JSON()\n", " xray_run = gr.Button(\"Run\")\n", " xray_run.click(\n", " xray_model,\n", " inputs=[disease, xray_scan],\n", " outputs=xray_results,\n", " api_name=\"xray_model\"\n", " )\n", "\n", " with gr.Tab(\"CT Scan\"):\n", " with gr.Row():\n", " ct_scan = gr.Image()\n", " ct_results = gr.JSON()\n", " ct_run = gr.Button(\"Run\")\n", " ct_run.click(\n", " ct_model,\n", " inputs=[disease, ct_scan],\n", " outputs=ct_results,\n", " api_name=\"ct_model\"\n", " )\n", "\n", " upload_btn = gr.Button(\"Upload Results\", variant=\"primary\")\n", " upload_btn.click(\n", " lambda ct, xr: None,\n", " inputs=[ct_results, xray_results],\n", " outputs=[],\n", " )\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

View File

@ -1,14 +1,13 @@
import gradio as gr
import random
import time
disease_values = [0.25, 0.5, 0.75]
def xray_model(diseases, img):
time.sleep(4)
return [{disease: random.random() for disease in diseases}]
return [{disease: disease_values[idx] for idx,disease in enumerate(diseases)}]
def ct_model(diseases, img):
time.sleep(3)
return [{disease: 0.1 for disease in diseases}]
with gr.Blocks() as demo:
@ -52,7 +51,7 @@ With this model you can lorem ipsum
upload_btn = gr.Button("Upload Results", variant="primary")
upload_btn.click(
lambda ct, xr: time.sleep(5),
lambda ct, xr: None,
inputs=[ct_results, xray_results],
outputs=[],
)

View File

@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: outbreak_forecast\n", "### Generate a plot based on 5 inputs.\n", " "]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio numpy matplotlib bokeh plotly altair"]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["import altair\n", "\n", "import gradio as gr\n", "from math import sqrt\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import plotly.express as px\n", "import pandas as pd\n", "\n", "\n", "def outbreak(plot_type, r, month, countries, social_distancing):\n", " months = [\"January\", \"February\", \"March\", \"April\", \"May\"]\n", " m = months.index(month)\n", " start_day = 30 * m\n", " final_day = 30 * (m + 1)\n", " x = np.arange(start_day, final_day + 1)\n", " pop_count = {\"USA\": 350, \"Canada\": 40, \"Mexico\": 300, \"UK\": 120}\n", " if social_distancing:\n", " r = sqrt(r)\n", " df = pd.DataFrame({\"day\": x})\n", " for country in countries:\n", " df[country] = x ** (r) * (pop_count[country] + 1)\n", "\n", " if plot_type == \"Matplotlib\":\n", " fig = plt.figure()\n", " plt.plot(df[\"day\"], df[countries].to_numpy())\n", " plt.title(\"Outbreak in \" + month)\n", " plt.ylabel(\"Cases\")\n", " plt.xlabel(\"Days since Day 0\")\n", " plt.legend(countries)\n", " return fig\n", " elif plot_type == \"Plotly\":\n", " fig = px.line(df, x=\"day\", y=countries)\n", " fig.update_layout(\n", " title=\"Outbreak in \" + month,\n", " xaxis_title=\"Cases\",\n", " yaxis_title=\"Days Since Day 0\",\n", " )\n", " return fig\n", " elif plot_type == \"Altair\":\n", " df = df.melt(id_vars=\"day\").rename(columns={\"variable\": \"country\"})\n", " fig = altair.Chart(df).mark_line().encode(x=\"day\", y='value', color='country')\n", " return fig\n", " else:\n", " raise ValueError(\"A plot type must be selected\")\n", "\n", "\n", "inputs = [\n", " gr.Dropdown([\"Matplotlib\", \"Plotly\", \"Altair\"], label=\"Plot Type\"),\n", " gr.Slider(1, 4, 3.2, label=\"R\"),\n", " gr.Dropdown([\"January\", \"February\", \"March\", \"April\", \"May\"], label=\"Month\"),\n", " gr.CheckboxGroup(\n", " [\"USA\", \"Canada\", \"Mexico\", \"UK\"], label=\"Countries\", value=[\"USA\", \"Canada\"]\n", " ),\n", " gr.Checkbox(label=\"Social Distancing?\"),\n", "]\n", "outputs = gr.Plot()\n", "\n", "demo = gr.Interface(\n", " fn=outbreak,\n", " inputs=inputs,\n", " outputs=outputs,\n", " examples=[\n", " [\"Matplotlib\", 2, \"March\", [\"Mexico\", \"UK\"], True],\n", " [\"Altair\", 2, \"March\", [\"Mexico\", \"Canada\"], True],\n", " [\"Plotly\", 3.6, \"February\", [\"Canada\", \"Mexico\", \"UK\"], False],\n", " ],\n", " cache_examples=True,\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: outbreak_forecast\n", "### Generate a plot based on 5 inputs.\n", " "]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio numpy matplotlib bokeh plotly altair"]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["import altair\n", "\n", "import gradio as gr\n", "from math import sqrt\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import plotly.express as px\n", "import pandas as pd\n", "\n", "\n", "def outbreak(plot_type, r, month, countries, social_distancing):\n", " months = [\"January\", \"February\", \"March\", \"April\", \"May\"]\n", " m = months.index(month)\n", " start_day = 30 * m\n", " final_day = 30 * (m + 1)\n", " x = np.arange(start_day, final_day + 1)\n", " pop_count = {\"USA\": 350, \"Canada\": 40, \"Mexico\": 300, \"UK\": 120}\n", " if social_distancing:\n", " r = sqrt(r)\n", " df = pd.DataFrame({\"day\": x})\n", " for country in countries:\n", " df[country] = x ** (r) * (pop_count[country] + 1)\n", "\n", " if plot_type == \"Matplotlib\":\n", " fig = plt.figure()\n", " plt.plot(df[\"day\"], df[countries].to_numpy())\n", " plt.title(\"Outbreak in \" + month)\n", " plt.ylabel(\"Cases\")\n", " plt.xlabel(\"Days since Day 0\")\n", " plt.legend(countries)\n", " return fig\n", " elif plot_type == \"Plotly\":\n", " fig = px.line(df, x=\"day\", y=countries)\n", " fig.update_layout(\n", " title=\"Outbreak in \" + month,\n", " xaxis_title=\"Cases\",\n", " yaxis_title=\"Days Since Day 0\",\n", " )\n", " return fig\n", " elif plot_type == \"Altair\":\n", " df = df.melt(id_vars=\"day\").rename(columns={\"variable\": \"country\"})\n", " fig = altair.Chart(df).mark_line().encode(x=\"day\", y='value', color='country')\n", " return fig\n", " else:\n", " raise ValueError(\"A plot type must be selected\")\n", "\n", "\n", "inputs = [\n", " gr.Dropdown([\"Matplotlib\", \"Plotly\", \"Altair\"], label=\"Plot Type\"),\n", " gr.Slider(1, 4, 3.2, label=\"R\"),\n", " gr.Dropdown([\"January\", \"February\", \"March\", \"April\", \"May\"], label=\"Month\"),\n", " gr.CheckboxGroup(\n", " [\"USA\", \"Canada\", \"Mexico\", \"UK\"], label=\"Countries\", value=[\"USA\", \"Canada\"]\n", " ),\n", " gr.Checkbox(label=\"Social Distancing?\"),\n", "]\n", "outputs = gr.Plot()\n", "\n", "demo = gr.Interface(\n", " fn=outbreak,\n", " inputs=inputs,\n", " outputs=outputs,\n", " examples=[\n", " [\"Matplotlib\", 2, \"March\", [\"Mexico\", \"UK\"], True],\n", " [\"Altair\", 2, \"March\", [\"Mexico\", \"Canada\"], True],\n", " [\"Plotly\", 3.6, \"February\", [\"Canada\", \"Mexico\", \"UK\"], False],\n", " ],\n", " cache_examples=True,\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n", "\n", "\n", "\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

View File

@ -70,3 +70,6 @@ demo = gr.Interface(
if __name__ == "__main__":
demo.launch()

View File

@ -10,7 +10,6 @@
"preview": "vite preview",
"test:snapshot": "pnpm exec playwright test snapshots/ --config=../../.config/playwright.config.js",
"test:browser": "pnpm exec playwright test test/ --config=../../.config/playwright.config.js",
"test:browser:full": "python test/create_demo_configs.py && pnpm exec playwright test test/ --config=../../.config/playwright.config.js",
"test:browser:debug": "pnpm exec playwright test test/ --debug --config=../../.config/playwright.config.js",
"build:css": "pollen -c pollen.config.cjs -o src/pollen-dev.css"
},
@ -21,8 +20,8 @@
"@gradio/button": "workspace:^0.0.1",
"@gradio/chart": "workspace:^0.0.1",
"@gradio/chatbot": "workspace:^0.0.1",
"@gradio/code": "workspace:^0.0.1",
"@gradio/client": "workspace:^0.1.2",
"@gradio/code": "workspace:^0.0.1",
"@gradio/file": "workspace:^0.0.1",
"@gradio/form": "workspace:^0.0.1",
"@gradio/gallery": "workspace:^0.0.1",
@ -42,6 +41,7 @@
"@gradio/upload-button": "workspace:^0.0.1",
"@gradio/utils": "workspace:^0.0.1",
"@gradio/video": "workspace:^0.0.1",
"@playwright/test": "^1.35.1",
"d3-dsv": "^3.0.1",
"mime-types": "^2.1.34",
"postcss": "^8.4.21",

View File

@ -1,12 +1,6 @@
import { test, expect } from "@playwright/test";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { test, expect } from "@gradio/tootils";
test("renders the correct elements", async ({ page }) => {
await mock_demo(page, "blocks_inputs");
await mock_api(page, [["hi dawood"]]);
await mock_theme(page);
await wait_for_page(page);
const textboxes = await page.getByLabel("Input");
const textboxOne = await textboxes.first();

View File

@ -1,12 +1,6 @@
import { test, expect, Page } from "@playwright/test";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { test } from "@gradio/tootils";
test("renders the correct elements", async ({ page }) => {
await mock_demo(page, "blocks_kinematics");
await mock_api(page, [[25, 45]]);
await mock_theme(page);
await wait_for_page(page);
await Promise.all([
page.click("button:has-text('Run')"),
page.waitForResponse("**/run/predict")

View File

@ -1,12 +1,6 @@
import { test, expect, Page } from "@playwright/test";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { test, expect } from "@gradio/tootils";
test("renders the correct elements", async ({ page }) => {
await mock_demo(page, "blocks_page_load");
await mock_api(page, [["Welcome! This page has loaded for Frank"]]);
await mock_theme(page);
await wait_for_page(page);
const textbox = await page.getByLabel("Name");
await textbox.fill("Frank");

View File

@ -1,11 +1,6 @@
import { test, expect, Page } from "@playwright/test";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { test, expect } from "@gradio/tootils";
test("renders the correct elements", async ({ page }) => {
await mock_demo(page, "blocks_xray");
await mock_theme(page);
await wait_for_page(page);
const description = await page.getByTestId("markdown");
await expect(description).toContainText("Detect Disease From Scan");
@ -17,25 +12,6 @@ test("renders the correct elements", async ({ page }) => {
});
test("can run an api request and display the data", async ({ page }) => {
await mock_demo(page, "blocks_xray");
await mock_api(page, [
[
{
Covid: 0.75,
"Lung Cancer": 0.25
}
],
[
{
Covid: 0.75,
"Lung Cancer": 0.25
}
]
]);
await mock_theme(page);
await wait_for_page(page);
await page.getByLabel("Covid").check();
await page.getByLabel("Lung Cancer").check();
@ -47,5 +23,5 @@ test("can run an api request and display the data", async ({ page }) => {
]);
const json = await page.getByTestId("json").first();
await expect(json).toContainText(`Covid: 0.75, Lung Cancer: 0.25`);
await expect(json).toContainText(`Covid: 0.25, Lung Cancer: 0.5`);
});

View File

@ -1,12 +1,6 @@
import { test, expect, Page } from "@playwright/test";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { test, expect } from "@gradio/tootils";
test("a component acts as both input and output", async ({ page }) => {
await mock_demo(page, "input_output");
await mock_api(page, [["tset"]]);
await mock_theme(page);
await wait_for_page(page);
const textbox = await page.getByLabel("Input-Output");
await textbox.fill("test");

View File

@ -1,12 +1,7 @@
import { test, expect, Page } from "@playwright/test";
import { BASE64_IMAGE, BASE64_AUDIO } from "./media_data";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { test, expect } from "@gradio/tootils";
import { BASE64_IMAGE } from "./media_data";
test("test inputs", async ({ page }) => {
await mock_demo(page, "kitchen_sink");
await mock_theme(page);
await wait_for_page(page);
const textbox = await page.getByLabel("Textbox").nth(0);
await expect(textbox).toHaveValue("Lorem ipsum");
@ -39,162 +34,7 @@ test("test inputs", async ({ page }) => {
await expect(image_data_cropper).toContain("cheetah1.jpg");
});
test("test outputs", async ({ page }) => {
await mock_demo(page, "kitchen_sink");
await mock_api(page, [
[
"the quick brown fox, selected:foo, baz",
{
label: "negative",
confidences: [
{
label: "negative",
confidence: 0.46153846153846156
},
{
label: "positive",
confidence: 0.38461538461538464
},
{
label: "neutral",
confidence: 0.15384615384615385
}
]
},
BASE64_AUDIO,
BASE64_IMAGE,
[
{
name: "worldt30a4ike.mp4",
data: ""
},
{
name: null,
data: null
}
],
[
["The", "art"],
["quick brown", "adj"],
["fox", "nn"],
["jumped", "vrb"],
["testing testing testing", null],
["over", "prp"],
["the", "art"],
["testing", null],
["lazy", "adj"],
["dogs", "nn"],
[".", "punc"],
["test 0", "test 0"],
["test 1", "test 1"],
["test 2", "test 2"],
["test 3", "test 3"],
["test 4", "test 4"],
["test 5", "test 5"],
["test 6", "test 6"],
["test 7", "test 7"],
["test 8", "test 8"],
["test 9", "test 9"]
],
[
["The testing testing testing", null],
["over", 0.6],
["the", 0.2],
["testing", null],
["lazy", -0.1],
["dogs", 0.4],
[".", 0],
["test", -1],
["test", -0.9],
["test", -0.8],
["test", -0.7],
["test", -0.6],
["test", -0.5],
["test", -0.4],
["test", -0.3],
["test", -0.2],
["test", -0.1],
["test", 0],
["test", 0.1],
["test", 0.2],
["test", 0.3],
["test", 0.4],
["test", 0.5],
["test", 0.6],
["test", 0.7],
["test", 0.8],
["test", 0.9]
],
{
items: {
item: [
{
id: "0001",
type: null,
is_good: false,
ppu: 0.55,
batters: {
batter: [
{
id: "1001",
type: "Regular"
},
{
id: "1002",
type: "Chocolate"
},
{
id: "1003",
type: "Blueberry"
},
{
id: "1004",
type: "Devil's Food"
}
]
},
topping: [
{
id: "5001",
type: "None"
},
{
id: "5002",
type: "Glazed"
},
{
id: "5005",
type: "Sugar"
},
{
id: "5007",
type: "Powdered Sugar"
},
{
id: "5006",
type: "Chocolate with Sprinkles"
},
{
id: "5003",
type: "Chocolate"
},
{
id: "5004",
type: "Maple"
}
]
}
]
}
},
"<button style='background-color: red'>Click Me: baz</button>"
]
]);
await mock_theme(page);
await wait_for_page(page);
test("test outputs", async ({ page, browser }) => {
const submit_button = await page.locator("button", { hasText: /Submit/ });
await Promise.all([
@ -203,16 +43,12 @@ test("test outputs", async ({ page }) => {
]);
const textbox = await page.getByLabel("Textbox").nth(2);
await expect(textbox).toHaveValue("the quick brown fox, selected:foo, baz");
await expect(textbox).toHaveValue(", selected:foo, bar");
const label = await page.getByTestId("label");
await expect(label).toContainText(`negative
negative
46%
positive
38%
neutral
15%`);
await expect(label).toContainText(
` Label positive positive 74% negative 26% neutral 0%`
);
const highlight_text_color_map = await page
.getByTestId("highlighted-text")
@ -227,9 +63,6 @@ test("test outputs", async ({ page }) => {
"The testing testing testing over the testing lazy dogs . test test test test test test test test test test test test test test test test test test test test"
);
// const click_me_button =await page.locator("button", { hasText: /Click Me: baz/ });
// click_me_button.click()
const json = await page.locator("data-testid=json");
await expect(json).toContainText(`{
items: {
@ -262,5 +95,10 @@ test("test outputs", async ({ page }) => {
const audio = await page.locator("audio").nth(0);
const audio_data = await audio.getAttribute("src");
await expect(audio_data).toEqual(BASE64_AUDIO);
await expect(
audio_data?.endsWith(
"gradio/92aff6ffe140da201a4a94cb3c3b9e1ff0b2a25a/cantina.wav"
)
).toBeTruthy();
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
import { test, expect, Page, Locator } from "@playwright/test";
import { mock_theme, wait_for_page, mock_api, mock_demo } from "./utils";
import { Page, Locator } from "@playwright/test";
import { test, expect } from "@gradio/tootils";
//taken from: https://github.com/microsoft/playwright/issues/20032
async function changeSlider(
@ -34,10 +34,6 @@ async function changeSlider(
}
test("slider release", async ({ page }) => {
await mock_demo(page, "slider_release");
await mock_api(page, [[70, null, 1]]);
await mock_theme(page);
await wait_for_page(page);
const slider = page.getByLabel("Slider");
await changeSlider(page, slider, slider, 0.7);
@ -47,6 +43,6 @@ test("slider release", async ({ page }) => {
const val = await slider.inputValue();
expect(parseInt(val)).toBeCloseTo(70);
expect(value).toHaveValue("70");
expect(parseInt(await value.inputValue())).toBeCloseTo(70);
expect(events).toHaveValue("1");
});

View File

@ -1,52 +0,0 @@
import type { Page } from "@playwright/test";
export function mock_theme(page: Page) {
return page.route("**/theme.css", (route) => {
return route.fulfill({
headers: {
"Access-Control-Allow-Origin": "*"
},
path: `./test/mocks/theme.css`
});
});
}
export async function wait_for_page(page: Page) {
await page.goto("http://localhost:9876");
await page.waitForResponse("**/theme.css");
}
export function mock_demo(page: Page, demo: string) {
return Promise.all([
page.route("**/config", (route) => {
return route.fulfill({
headers: {
"Access-Control-Allow-Origin": "*"
},
path: `../../demo/${demo}/config.json`
});
}),
page.route("**/info", (route) => {
return route.fulfill({
headers: {
"Access-Control-Allow-Origin": "*"
},
path: `./test/mocks/info-${demo}.json`
});
})
]);
}
export function mock_api(page: Page, body?: Array<unknown>) {
return page.route("**/run/predict", (route) => {
const id = JSON.parse(route.request().postData()!).fn_index;
return route.fulfill({
headers: {
"Access-Control-Allow-Origin": "*"
},
body: JSON.stringify({
data: body === undefined ? [] : body[id]
})
});
});
}

View File

@ -1,3 +1,6 @@
import { test as base } from "@playwright/test";
import { basename } from "path";
export function get_text<T extends HTMLElement>(el: T) {
return el.innerText.trim();
}
@ -6,4 +9,19 @@ export function wait(n: number) {
return new Promise((r) => setTimeout(r, n));
}
export const test = base.extend<{ setup: void }>({
setup: [
async ({ page }, use, testInfo) => {
const { file } = testInfo;
const test = basename(file, ".spec.ts");
await page.goto(`localhost:7879/${test}`);
await use();
},
{ auto: true }
]
});
export { expect } from "@playwright/test";
export * from "./render";

View File

@ -19,8 +19,9 @@
"test": "pnpm --filter @gradio/client build && vitest dev --config .config/vitest.config.ts",
"test:run": "pnpm --filter @gradio/client build && vitest run --config .config/vitest.config.ts",
"test:node": "TEST_MODE=node pnpm vitest run --config .config/vitest.config.ts",
"test:browser": "pnpm --filter @gradio/app test:browser:full",
"test:browser": "pnpm --filter @gradio/app test:browser",
"test:browser:full": "run-s build test:browser",
"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"
@ -33,7 +34,7 @@
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.1",
"@gradio/tootils": "workspace:^0.0.1",
"@playwright/test": "^1.27.1",
"@playwright/test": "^1.35.1",
"@sveltejs/vite-plugin-svelte": "^1.0.0-next.44",
"@tailwindcss/forms": "^0.5.0",
"@testing-library/dom": "^8.11.3",
@ -47,7 +48,7 @@
"msw": "^1.0.0",
"node-html-parser": "^5.3.3",
"npm-run-all": "^4.1.5",
"playwright": "^1.27.1",
"playwright": "^1.35.1",
"plotly.js-dist-min": "^2.10.1",
"polka": "^1.0.0-next.22",
"pollen-css": "^4.6.1",
@ -67,7 +68,7 @@
"tailwindcss": "^3.1.6",
"tinyspy": "^0.3.0",
"typescript": "^4.7.4",
"vite": "^4.2.1",
"vite": "^4.3.9",
"vitest": "^0.29.8"
},
"devDependencies": {

88
pnpm-lock.yaml generated
View File

@ -18,11 +18,11 @@ importers:
specifier: workspace:^0.0.1
version: link:js/tootils
'@playwright/test':
specifier: ^1.27.1
version: 1.27.1
specifier: ^1.35.1
version: 1.35.1
'@sveltejs/vite-plugin-svelte':
specifier: ^1.0.0-next.44
version: 1.0.0-next.44(svelte@3.59.1)(vite@4.2.1)
version: 1.0.0-next.44(svelte@3.59.1)(vite@4.3.9)
'@tailwindcss/forms':
specifier: ^0.5.0
version: 0.5.0(tailwindcss@3.1.6)
@ -60,8 +60,8 @@ importers:
specifier: ^4.1.5
version: 4.1.5
playwright:
specifier: ^1.27.1
version: 1.27.1
specifier: ^1.35.1
version: 1.35.1
plotly.js-dist-min:
specifier: ^2.10.1
version: 2.11.1
@ -120,11 +120,11 @@ importers:
specifier: ^4.7.4
version: 4.7.4
vite:
specifier: ^4.2.1
version: 4.2.1(@types/node@17.0.14)
specifier: ^4.3.9
version: 4.3.9(@types/node@17.0.14)
vitest:
specifier: ^0.29.8
version: 0.29.8(happy-dom@9.20.3)(playwright@1.27.1)
version: 0.29.8(happy-dom@9.20.3)(playwright@1.35.1)
devDependencies:
'@types/three':
specifier: ^0.138.0
@ -190,7 +190,7 @@ importers:
version: 5.0.4
vite:
specifier: ^4.3.0
version: 4.3.5(@types/node@17.0.14)
version: 4.3.5
js/accordion: {}
@ -277,6 +277,9 @@ importers:
'@gradio/video':
specifier: workspace:^0.0.1
version: link:../video
'@playwright/test':
specifier: ^1.35.1
version: 1.35.1
d3-dsv:
specifier: ^3.0.1
version: 3.0.1
@ -1580,13 +1583,15 @@ packages:
resolution: {integrity: sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==}
dev: false
/@playwright/test@1.27.1:
resolution: {integrity: sha512-mrL2q0an/7tVqniQQF6RBL2saskjljXzqNcCOVMUjRIgE6Y38nCNaP+Dc2FBW06bcpD3tqIws/HT9qiMHbNU0A==}
engines: {node: '>=14'}
/@playwright/test@1.35.1:
resolution: {integrity: sha512-b5YoFe6J9exsMYg0pQAobNDR85T1nLumUYgUTtKm4d21iX2L7WqKq9dW8NGJ+2vX0etZd+Y7UeuqsxDXm9+5ZA==}
engines: {node: '>=16'}
hasBin: true
dependencies:
'@types/node': 17.0.14
playwright-core: 1.27.1
playwright-core: 1.35.1
optionalDependencies:
fsevents: 2.3.2
dev: false
/@polka/url@1.0.0-next.21:
@ -1689,7 +1694,7 @@ packages:
svelte: 3.57.0
tiny-glob: 0.2.9
undici: 5.22.0
vite: 4.3.5(@types/node@17.0.14)
vite: 4.3.5
transitivePeerDependencies:
- supports-color
dev: true
@ -1717,7 +1722,7 @@ packages:
- supports-color
dev: true
/@sveltejs/vite-plugin-svelte@1.0.0-next.44(svelte@3.59.1)(vite@4.2.1):
/@sveltejs/vite-plugin-svelte@1.0.0-next.44(svelte@3.59.1)(vite@4.3.9):
resolution: {integrity: sha512-n+sssEWbzykPS447FmnNyU5GxEhrBPDVd0lxNZnxRGz9P6651LjjwAnISKr3CKgT9v8IybP8VD0n2i5XzbqExg==}
engines: {node: ^14.13.1 || >= 16}
peerDependencies:
@ -1735,7 +1740,7 @@ packages:
magic-string: 0.26.1
svelte: 3.59.1
svelte-hmr: 0.14.11(svelte@3.59.1)
vite: 4.2.1(@types/node@17.0.14)
vite: 4.3.9(@types/node@17.0.14)
transitivePeerDependencies:
- supports-color
dev: false
@ -1753,7 +1758,7 @@ packages:
magic-string: 0.30.0
svelte: 3.57.0
svelte-hmr: 0.15.1(svelte@3.57.0)
vite: 4.3.5(@types/node@17.0.14)
vite: 4.3.5
vitefu: 0.2.4(vite@4.3.5)
transitivePeerDependencies:
- supports-color
@ -4984,19 +4989,19 @@ packages:
pathe: 1.1.0
dev: false
/playwright-core@1.27.1:
resolution: {integrity: sha512-9EmeXDncC2Pmp/z+teoVYlvmPWUC6ejSSYZUln7YaP89Z6lpAaiaAnqroUt/BoLo8tn7WYShcfaCh+xofZa44Q==}
engines: {node: '>=14'}
/playwright-core@1.35.1:
resolution: {integrity: sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==}
engines: {node: '>=16'}
hasBin: true
dev: false
/playwright@1.27.1:
resolution: {integrity: sha512-xXYZ7m36yTtC+oFgqH0eTgullGztKSRMb4yuwLPl8IYSmgBM88QiB+3IWb1mRIC9/NNwcgbG0RwtFlg+EAFQHQ==}
engines: {node: '>=14'}
/playwright@1.35.1:
resolution: {integrity: sha512-NbwBeGJLu5m7VGM0+xtlmLAH9VUfWwYOhUi/lSEDyGg46r1CA9RWlvoc5yywxR9AzQb0mOCm7bWtOXV7/w43ZA==}
engines: {node: '>=16'}
hasBin: true
requiresBuild: true
dependencies:
playwright-core: 1.27.1
playwright-core: 1.35.1
dev: false
/plotly.js-dist-min@2.11.1:
@ -5507,14 +5512,6 @@ packages:
fsevents: 2.3.2
dev: true
/rollup@3.20.2:
resolution: {integrity: sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
hasBin: true
optionalDependencies:
fsevents: 2.3.2
dev: false
/rollup@3.21.6:
resolution: {integrity: sha512-SXIICxvxQxR3D4dp/3LDHZIJPC8a4anKMHd4E3Jiz2/JnY+2bEjqrOokAauc5ShGVNFHlEFjBXAXlaxkJqIqSg==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
@ -7026,7 +7023,7 @@ packages:
mlly: 1.2.0
pathe: 1.1.0
picocolors: 1.0.0
vite: 4.3.5(@types/node@17.0.14)
vite: 4.3.9(@types/node@17.0.14)
transitivePeerDependencies:
- '@types/node'
- less
@ -7061,8 +7058,8 @@ packages:
fsevents: 2.3.2
dev: true
/vite@4.2.1(@types/node@17.0.14):
resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==}
/vite@4.3.5:
resolution: {integrity: sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
@ -7086,17 +7083,15 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 17.0.14
esbuild: 0.17.14
postcss: 8.4.21
resolve: 1.22.1
rollup: 3.20.2
postcss: 8.4.23
rollup: 3.21.6
optionalDependencies:
fsevents: 2.3.2
dev: false
dev: true
/vite@4.3.5(@types/node@17.0.14):
resolution: {integrity: sha512-0gEnL9wiRFxgz40o/i/eTBwm+NEbpUeTWhzKrZDSdKm6nplj+z4lKz8ANDgildxHm47Vg8EUia0aicKbawUVVA==}
/vite@4.3.9(@types/node@17.0.14):
resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==}
engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true
peerDependencies:
@ -7126,6 +7121,7 @@ packages:
rollup: 3.21.6
optionalDependencies:
fsevents: 2.3.2
dev: false
/vitefu@0.2.4(vite@4.3.5):
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
@ -7135,10 +7131,10 @@ packages:
vite:
optional: true
dependencies:
vite: 4.3.5(@types/node@17.0.14)
vite: 4.3.5
dev: true
/vitest@0.29.8(happy-dom@9.20.3)(playwright@1.27.1):
/vitest@0.29.8(happy-dom@9.20.3)(playwright@1.35.1):
resolution: {integrity: sha512-JIAVi2GK5cvA6awGpH0HvH/gEG9PZ0a/WoxdiV3PmqK+3CjQMf8c+J/Vhv4mdZ2nRyXFw66sAg6qz7VNkaHfDQ==}
engines: {node: '>=v14.16.0'}
hasBin: true
@ -7185,14 +7181,14 @@ packages:
local-pkg: 0.4.3
pathe: 1.1.0
picocolors: 1.0.0
playwright: 1.27.1
playwright: 1.35.1
source-map: 0.6.1
std-env: 3.3.2
strip-literal: 1.0.1
tinybench: 2.4.0
tinypool: 0.4.0
tinyspy: 1.1.1
vite: 4.2.1(@types/node@17.0.14)
vite: 4.3.9(@types/node@17.0.14)
vite-node: 0.29.8(@types/node@17.0.14)
why-is-node-running: 2.2.2
transitivePeerDependencies: