diff --git a/.config/playwright.config.js b/.config/playwright.config.js index 493b102046..cf8fb79278 100644 --- a/.config/playwright.config.js +++ b/.config/playwright.config.js @@ -3,7 +3,7 @@ export default { screenshot: "only-on-failure", trace: "retain-on-failure" }, - // testMatch: /.*.spec.ts/, + testMatch: /.*.spec.ts/, testDir: "..", globalSetup: "./playwright-setup.js" }; diff --git a/js/app/src/components/Label/Label.svelte b/js/app/src/components/Label/Label.svelte index 347f5e5a86..af26d4c8f9 100644 --- a/js/app/src/components/Label/Label.svelte +++ b/js/app/src/components/Label/Label.svelte @@ -19,7 +19,7 @@ export let scale: number | null = null; export let min_width: number | undefined = undefined; export let loading_status: LoadingStatus; - export let show_label: boolean; + export let show_label: boolean = true; export let selectable: boolean = false; const dispatch = createEventDispatcher<{ change: undefined }>(); diff --git a/js/app/test/components.test.ts b/js/app/test/components.test.ts new file mode 100644 index 0000000000..387a012b74 --- /dev/null +++ b/js/app/test/components.test.ts @@ -0,0 +1,231 @@ +import { + afterAll, + afterEach, + beforeAll, + beforeEach, + describe, + expect, + test +} from "vitest"; +import { render, cleanup } from "@gradio/tootils"; +import { setupi18n } from "../src/i18n"; + +import AnnotatedImage from "../src/components/AnnotatedImage/AnnotatedImage.svelte"; +import Audio from "../src/components/Audio/Audio.svelte"; +import Chatbot from "../src/components/Chatbot/Chatbot.svelte"; +import Checkbox from "../src/components/Checkbox/Checkbox.svelte"; +import CheckboxGroup from "../src/components/CheckboxGroup/CheckboxGroup.svelte"; +import ColorPicker from "../src/components/ColorPicker/ColorPicker.svelte"; +import DataFrame from "../src/components/DataFrame/DataFrame.svelte"; +import Dropdown from "../src/components/Dropdown/Dropdown.svelte"; +import File from "../src/components/File/File.svelte"; +import Gallery from "../src/components/Gallery/Gallery.svelte"; +import HTML from "../src/components/HTML/HTML.svelte"; +import HighlightedText from "../src/components/HighlightedText/HighlightedText.svelte"; +import Json from "../src/components/Json/Json.svelte"; +import Label from "../src/components/Label/Label.svelte"; +import Markdown from "../src/components/Markdown/Markdown.svelte"; +import Model3D from "../src/components/Model3D/Model3D.svelte"; +import Number from "../src/components/Number/Number.svelte"; +import Radio from "../src/components/Radio/Radio.svelte"; +import Slider from "../src/components/Slider/Slider.svelte"; +import Textbox from "../src/components/Textbox/Textbox.svelte"; +import TimeSeries from "../src/components/TimeSeries/TimeSeries.svelte"; +import UploadButton from "../src/components/UploadButton/UploadButton.svelte"; +import Video from "../src/components/Video/Video.svelte"; +import { LoadingStatus } from "../src/components/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" +}; + +const components = [ + ["AnnotatedImage", AnnotatedImage, { height: 100, width: 100, value: null }], + ["Audio", Audio, {}], + // ["Button", Button, {}], + ["Chatbot", Chatbot, {}], + ["Checkbox", Checkbox, {}], + ["CheckboxGroup", CheckboxGroup, { choices: ["a", "b", "c"] }], + // ["Code", Code, {}], + ["ColorPicker", ColorPicker, {}], + [ + "DataFrame", + DataFrame, + { value: [[1, 2, 3]], col_count: [3, "fixed"], row_count: [3, "fixed"] } + ], + // ["Dataset", Dataset, {}], + ["Dropdown", Dropdown, { choices: ["a", "b", "c"] }], + ["File", File, {}], + ["Gallery", Gallery, {}], + ["HTML", HTML, {}], + ["HighlightedText", HighlightedText, {}], + // ["Image",, {} Image], + ["Json", Json, {}], + ["Label", Label, {}], + ["Markdown", Markdown, {}], + ["Model3D", Model3D, {}], + ["Number", Number, {}], + // ["Plot", Plot, {}], + ["Radio", Radio, {}], + ["Slider", Slider, {}], + ["Textbox", Textbox, {}], + ["TimeSeries", TimeSeries, {}], + ["UploadButton", UploadButton, {}], + ["Video", Video, {}] +] as const; + +describe("all components should apply provided class names", () => { + beforeAll(() => { + setupi18n(); + }); + + afterEach(() => { + cleanup(); + }); + + components.forEach(([name, component, props]) => { + test(name, async () => { + const { container } = await render(component, { + ...props, + loading_status, + elem_classes: ["test-class"] + }); + + const elem = container.querySelector(`.test-class`); + expect(elem).not.toBeNull(); + }); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); + +describe("all components should apply provided id", () => { + beforeAll(() => { + setupi18n(); + }); + + afterEach(() => { + cleanup(); + }); + + components.forEach(([name, component, props]) => { + test(name, async () => { + const { container } = await render(component, { + ...props, + loading_status, + elem_id: "test-id" + }); + + const elem = container.querySelector(`#test-id`); + expect(elem).not.toBeNull(); + }); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); + +describe("all components should be invisible when visible=false", () => { + beforeAll(() => { + setupi18n(); + }); + + afterEach(() => { + cleanup(); + }); + + components.forEach(([name, component, props]) => { + test(name, async () => { + const { container } = await render(component, { + ...props, + loading_status, + elem_id: "test-id", + visible: false + }); + + const elem = container.querySelector(`#test-id`); + + expect(elem).toHaveClass("hide-container"); + }); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); + +describe("all components should have the appropriate label when set via the `label` prop", () => { + beforeAll(() => { + setupi18n(); + }); + + afterEach(() => { + cleanup(); + }); + + components + .filter(([name]) => name !== "Markdown" && name !== "HTML") + .forEach(([name, component, props]) => { + test(name, async () => { + const { getAllByText } = await render(component, { + ...props, + loading_status, + label: name + "LABEL_TEST" + }); + + const elems = getAllByText(name + "LABEL_TEST"); + + expect(elems.length).toBeGreaterThan(0); + }); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); + +describe("all components should hide their label when `show_label=false`", () => { + components + .filter(([name]) => name !== "Markdown" && name !== "HTML") + .forEach(([name, component, props]) => { + test.todo(name); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); + +describe("all components should show their label when `show_label=true`", () => { + components + .filter(([name]) => name !== "Markdown" && name !== "HTML") + .forEach(([name, component, props]) => { + test.todo(name); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); + +describe("all components should hide their container when `container=false`", () => { + components + .filter(([name]) => name !== "Markdown" && name !== "HTML") + .forEach(([name, component, props]) => { + test.todo(name); + }); + + ["Button", "Code", "Image", "Plot"].forEach((name) => { + test.todo(name); + }); +}); diff --git a/js/app/test/tests.md b/js/app/test/tests.md new file mode 100644 index 0000000000..f3ca1cafe1 --- /dev/null +++ b/js/app/test/tests.md @@ -0,0 +1,142 @@ +# Test Coverage + +Just a little reference docs to understand what is tested/ needs testing. Perhaps temporary until we are in a better place. + +## Interface + +## Flagging +## Blocks +## Block Layouts +## Themes + +## Components + +### Props/kwargs + +| Component | `value` | `visible` | `elem_id` | `elem_classes` | `container` | `label` | `show_label` | +| --------------- | --------------- | ---------------- | ---------------- | ------------------- | ----------------- | --------- | ---------------| +| AnnotatedImage | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Audio | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| BarPlot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Button | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Chatbot | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Checkbox | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| CheckboxGroup | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| ClearButton | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Code | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| ColorPicker | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Dataframe | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Dropdown | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| File | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Gallery | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| HTML | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| HighlightedText | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Image | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` |  +| JSON | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Label | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Lineplot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Markdown | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Model3D | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Number | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Plot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Radio | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| ScatterPlot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Slider | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Textbox | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Timeseries | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| UploadButton | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | +| Video | `❌` | `✅` | `✅` | `✅` | `❌` | `✅` | `❌` | + +### Events + +| Component | `value` | `visible` | `elem_id` | `elem_classes` | `container` | `label` | `show_label` | +| --------------- | --------------- | ---------------- | ---------------- | ------------------- | ----------------- | --------- | ---------------| +| AnnotatedImage | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Audio | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| BarPlot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Button | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Chatbot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Checkbox | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| CheckboxGroup | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| ClearButton | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Code | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| ColorPicker | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Dataframe | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Dataset | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Dropdown | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| File | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Gallery | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| HTML | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| HighlightedText | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Image | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` |  +| Interpretation | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| JSON | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Label | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Lineplot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Markdown | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Model3D | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Number | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Plot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Radio | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| ScatterPlot | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Slider | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| State | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Textbox | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Timeseries | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| UploadButton | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | +| Video | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | `❌` | + +### `AnnotatedImage` +### `Audio` +### `BarPlot` +### `Button` +### `Chatbot` +### `Checkbox` +### `CheckboxGroup` +### `ClearButton` +### `Code` +### `ColorPicker` +### `Dataframe` +### `Dataset` +### `Dropdown` +### `File` +### `Gallery` +### `HTML` +### `HighlightedText` +### `Image` +### `Interpretation` +### `JSON` +### `Label` +### `Lineplot` +### `Markdown` +### `Model3D` +### `Number` +### `Plot` +### `Radio` +### `ScatterPlot` +### `Slider` +### `State` +### `Textbox` +### `Timeseries` +### `UploadButton` +### `Video` + +## Helpers + +### Error +### load +### Examples +### Progress +### update +### make_waveform +### EventData + +## Routes +### `Request` +### `mount_gradio_app` + +## Clients + +### Python (`gradio_client`) + +### JavaScript (`@gradio/client`) diff --git a/js/app/vite.config.ts b/js/app/vite.config.ts index fd6901ad98..68af0e6534 100644 --- a/js/app/vite.config.ts +++ b/js/app/vite.config.ts @@ -145,6 +145,7 @@ export default defineConfig(({ mode }) => { handle_ce_css() ], test: { + setupFiles: [resolve(__dirname, "../../.config/setup_vite_tests.ts")], environment: TEST_MODE, include: TEST_MODE === "node" diff --git a/js/button/src/Button.svelte b/js/button/src/Button.svelte index 38a54f4406..c12db5e646 100644 --- a/js/button/src/Button.svelte +++ b/js/button/src/Button.svelte @@ -11,7 +11,7 @@