Repository: gradio-app/gradio

Issue:
accordion launches as open even when open = False since gradio 4.20
### Describe the bug

congrats for the work on gradio 4.20!!

a bug seems to have appeared: 
accordion launches as open even when open = False since gradio 4.20
parameter open = False seems not to work anymore

I didn't have the bug in gradio 4.17

### Have you searched existing issues?  🔎

- [X] I have searched and found no existing issues

### Reproduction

 accordion = gr.Accordion(
            label="liste des fichiers",
            visible=True,
            open=False,
 )


### Screenshot

_No response_

### Logs

_No response_

### System Info

```shell
gradio 4.20

safari, chrome, iOS, mac : the bug is everywhere
```


### Severity

I can work around it


Discussion:

Resolving patch:
diff --git a/demo/audio_debugger/run.py b/demo/audio_debugger/run.py
--- a/demo/audio_debugger/run.py
+++ b/demo/audio_debugger/run.py
@@ -9,18 +9,32 @@
     with gr.Tab("Audio"):
         gr.Audio(audio_file)
     with gr.Tab("Interface"):
-        gr.Interface(lambda x:x, "audio", "audio", examples=[audio_file], cache_examples=True)
+        gr.Interface(
+            lambda x: x, "audio", "audio", examples=[audio_file], cache_examples=True
+        )
     with gr.Tab("Streaming"):
-        gr.Interface(lambda x:x, gr.Audio(streaming=True), "audio", examples=[audio_file], cache_examples=True)
+        gr.Interface(
+            lambda x: x,
+            gr.Audio(streaming=True),
+            "audio",
+            examples=[audio_file],
+            cache_examples=True,
+        )
     with gr.Tab("console"):
         ip = gr.Textbox(label="User IP Address")
-        gr.Interface(lambda cmd:subprocess.run([cmd], capture_output=True, shell=True).stdout.decode('utf-8').strip(), "text", "text")
-        
+        gr.Interface(
+            lambda cmd: subprocess.run([cmd], capture_output=True, shell=True)
+            .stdout.decode("utf-8")
+            .strip(),
+            "text",
+            "text",
+        )
+
     def get_ip(request: gr.Request):
         return request.client.host
-    
+
     demo.load(get_ip, None, ip)
-        
+
 if __name__ == "__main__":
     demo.queue()
     demo.launch()
diff --git a/demo/hello_blocks/run.py b/demo/hello_blocks/run.py
--- a/demo/hello_blocks/run.py
+++ b/demo/hello_blocks/run.py
@@ -1,8 +1,10 @@
 import gradio as gr
 
+
 def greet(name):
     return "Hello " + name + "!"
 
+
 with gr.Blocks() as demo:
     name = gr.Textbox(label="Name")
     output = gr.Textbox(label="Output Box")
@@ -10,4 +12,4 @@ def greet(name):
     greet_btn.click(fn=greet, inputs=name, outputs=output, api_name="greet")
 
 if __name__ == "__main__":
-    demo.launch()
\ No newline at end of file
+    demo.launch()


Test patch:
diff --git a/js/app/src/init.test.ts b/js/app/src/init.test.ts
new file mode 100644
--- /dev/null
+++ b/js/app/src/init.test.ts
@@ -0,0 +1,521 @@
+import { describe, test, expect, vi } from "vitest";
+import { spy } from "tinyspy";
+import { setupServer } from "msw/node";
+import { http, HttpResponse } from "msw";
+import type { client_return } from "@gradio/client";
+import { Dependency, TargetMap } from "./types";
+import {
+	process_frontend_fn,
+	create_target_meta,
+	determine_interactivity,
+	process_server_fn,
+	get_component
+} from "./init";
+
+describe("process_frontend_fn", () => {
+	test("empty source code returns null", () => {
+		const source = "";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		expect(fn).toBe(null);
+	});
+
+	test("falsey source code returns null: false", () => {
+		const source = false;
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		expect(fn).toBe(null);
+	});
+
+	test("falsey source code returns null: undefined", () => {
+		const source = undefined;
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		expect(fn).toBe(null);
+	});
+
+	test("falsey source code returns null: null", () => {
+		const source = null;
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		expect(fn).toBe(null);
+	});
+
+	test("source code returns a function", () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		expect(typeof fn).toBe("function");
+	});
+
+	test("arrays of values can be passed to the generated function", async () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		if (fn) {
+			await expect(fn([1])).resolves.toEqual([1]);
+		}
+	});
+
+	test("arrays of many values can be passed", async () => {
+		const source = "(...args) => args";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		if (fn) {
+			await expect(fn([1, 2, 3, 4, 5, 6])).resolves.toEqual([1, 2, 3, 4, 5, 6]);
+		}
+	});
+
+	test("The generated function returns a promise", () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		if (fn) {
+			expect(fn([1])).toBeInstanceOf(Promise);
+		}
+	});
+
+	test("The generated function is callable and returns the expected value", async () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		if (fn) {
+			await expect(fn([1])).resolves.toEqual([1]);
+		}
+	});
+
+	test("The return value of the function is wrapped in an array if there is no backend function and the input length is 1", async () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, false, 1, 1);
+		if (fn) {
+			await expect(fn([1])).resolves.toEqual([1]);
+		}
+	});
+
+	test("The return value of the function is not wrapped in an array if there is no backend function and the input length is greater than 1", async () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, false, 2, 2);
+		if (fn) {
+			await expect(fn([1])).resolves.toEqual(1);
+		}
+	});
+
+	test("The return value of the function is wrapped in an array if there is a backend function and the input length is 1", async () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, true, 1, 1);
+		if (fn) {
+			await expect(fn([1])).resolves.toEqual([1]);
+		}
+	});
+
+	test("The return value of the function is not wrapped in an array if there is a backend function and the input length is greater than 1", async () => {
+		const source = "(arg) => arg";
+
+		const fn = process_frontend_fn(source, true, 2, 2);
+		if (fn) {
+			await expect(fn([1])).resolves.toEqual(1);
+		}
+	});
+});
+
+describe("create_target_meta", () => {
+	test("creates a target map", () => {
+		const targets: Dependency["targets"] = [
+			[1, "change"],
+			[2, "input"],
+			[3, "load"]
+		];
+		const fn_index = 0;
+		const target_map = {};
+
+		const result = create_target_meta(targets, fn_index, target_map);
+		expect(result).toEqual({
+			1: { change: [0] },
+			2: { input: [0] },
+			3: { load: [0] }
+		});
+	});
+
+	test("if the target already exists, it adds the new trigger to the list", () => {
+		const targets: Dependency["targets"] = [
+			[1, "change"],
+			[1, "input"],
+			[1, "load"]
+		];
+		const fn_index = 1;
+		const target_map: TargetMap = {
+			1: { change: [0] }
+		};
+
+		const result = create_target_meta(targets, fn_index, target_map);
+		expect(result).toEqual({
+			1: { change: [0, 1], input: [1], load: [1] }
+		});
+	});
+
+	test("if the trigger already exists, it adds the new function to the list", () => {
+		const targets: Dependency["targets"] = [
+			[1, "change"],
+			[2, "change"],
+			[3, "change"]
+		];
+		const fn_index = 1;
+		const target_map: TargetMap = {
+			1: { change: [0] },
+			2: { change: [0] },
+			3: { change: [0] }
+		};
+
+		const result = create_target_meta(targets, fn_index, target_map);
+		expect(result).toEqual({
+			1: { change: [0, 1] },
+			2: { change: [0, 1] },
+			3: { change: [0, 1] }
+		});
+	});
+
+	test("if the target and trigger already exist, it adds the new function to the list", () => {
+		const targets: Dependency["targets"] = [[1, "change"]];
+		const fn_index = 1;
+		const target_map: TargetMap = {
+			1: { change: [0] }
+		};
+
+		const result = create_target_meta(targets, fn_index, target_map);
+		expect(result).toEqual({
+			1: { change: [0, 1] }
+		});
+	});
+
+	test("if the target, trigger and function id already exist, it does not add duplicates", () => {
+		const targets: Dependency["targets"] = [[1, "change"]];
+		const fn_index = 0;
+		const target_map: TargetMap = {
+			1: { change: [0] }
+		};
+
+		const result = create_target_meta(targets, fn_index, target_map);
+		expect(result).toEqual({
+			1: { change: [0] }
+		});
+	});
+});
+
+describe("determine_interactivity", () => {
+	test("returns true if the prop is interactive = true", () => {
+		const result = determine_interactivity(
+			0,
+			true,
+			"hi",
+			new Set([0]),
+			new Set([2])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns false if the prop is interactive = false", () => {
+		const result = determine_interactivity(
+			0,
+			false,
+			"hi",
+			new Set([0]),
+			new Set([2])
+		);
+		expect(result).toBe(false);
+	});
+
+	test("returns true if the component is an input", () => {
+		const result = determine_interactivity(
+			0,
+			undefined,
+			"hi",
+			new Set([0]),
+			new Set([2])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns true if the component is not an input or output and the component has no default value: empty string", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			"",
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns true if the component is not an input or output and the component has no default value: empty array", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			[],
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns true if the component is not an input or output and the component has no default value: boolean", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			false,
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns true if the component is not an input or output and the component has no default value: undefined", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			undefined,
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns true if the component is not an input or output and the component has no default value: null", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			null,
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns true if the component is not an input or output and the component has no default value: 0", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			0,
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(true);
+	});
+
+	test("returns false if the component is not an input or output and the component has a default value", () => {
+		const result = determine_interactivity(
+			2,
+			undefined,
+			"hello",
+			new Set([0]),
+			new Set([1])
+		);
+		expect(result).toBe(false);
+	});
+});
+
+describe("process_server_fn", () => {
+	test("returns an object", () => {
+		const result = process_server_fn(1, ["fn1", "fn2"], {} as any);
+		expect(result).toBeTypeOf("object");
+	});
+
+	test("returns an object with the correct keys", () => {
+		const result = process_server_fn(1, ["fn1", "fn2"], {} as any);
+		expect(Object.keys(result)).toEqual(["fn1", "fn2"]);
+	});
+
+	test("returns an object with the correct keys and values", () => {
+		const app = {
+			component_server: async (id: number, fn: string, args: any) => {
+				return args;
+			}
+		} as client_return;
+
+		const result = process_server_fn(1, ["fn1", "fn2"], app);
+		expect(Object.keys(result)).toEqual(["fn1", "fn2"]);
+
+		expect(result.fn1).toBeInstanceOf(Function);
+		expect(result.fn2).toBeInstanceOf(Function);
+	});
+
+	test("returned server functions should resolve to a promise", async () => {
+		const app = {
+			component_server: async (id: number, fn: string, args: any) => {
+				return args;
+			}
+		} as client_return;
+
+		const result = process_server_fn(1, ["fn1", "fn2"], app);
+		const response = result.fn1("hello");
+		expect(response).toBeInstanceOf(Promise);
+	});
+
+	test("the functions call the clients component_server function with the correct arguments ", async () => {
+		const mock = spy(async (id: number, fn: string, args: any) => {
+			return args;
+		});
+		const app = {
+			component_server: mock as any
+		} as client_return;
+
+		const result = process_server_fn(1, ["fn1", "fn2"], app as client_return);
+		const response = await result.fn1("hello");
+		expect(response).toBe("hello");
+		expect(mock.calls).toEqual([[1, "fn1", "hello"]]);
+	});
+
+	test("if there are no server functions, it returns an empty object", () => {
+		const result = process_server_fn(1, undefined, {} as any);
+		expect(result).toEqual({});
+	});
+});
+
+describe("get_component", () => {
+	test("returns an object", () => {
+		const result = get_component("test-component-one", "class_id", "root", []);
+		expect(result.component).toBeTypeOf("object");
+	});
+
+	test("returns an object with the correct keys", () => {
+		const result = get_component("test-component-one", "class_id", "root", []);
+		expect(Object.keys(result)).toEqual([
+			"component",
+			"name",
+			"example_components"
+		]);
+	});
+
+	test("the component key is a promise", () => {
+		const result = get_component("test-component-one", "class_id", "root", []);
+		expect(result.component).toBeInstanceOf(Promise);
+	});
+
+	test("the resolved component key is an object", async () => {
+		const result = get_component("test-component-one", "class_id", "root", []);
+		const o = await result.component;
+
+		expect(o).toBeTypeOf("object");
+	});
+
+	test("getting the same component twice should return the same promise", () => {
+		const result = get_component("test-component-one", "class_id", "root", []);
+		const result_two = get_component(
+			"test-component-one",
+			"class_id",
+			"root",
+			[]
+		);
+
+		expect(result.component).toBe(result_two.component);
+	});
+
+	test("if example components are not provided, the  example_components key is undefined", async () => {
+		const result = get_component("dataset", "class_id", "root", []);
+		expect(result.example_components).toBe(undefined);
+	});
+
+	test("if the type is not a dataset, the  example_components key is undefined", async () => {
+		const result = get_component("test-component-one", "class_id", "root", []);
+		expect(result.example_components).toBe(undefined);
+	});
+
+	test("when the type is a dataset, returns an object with the correct keys and values and example components", () => {
+		const result = get_component(
+			"dataset",
+			"class_id",
+			"root",
+			[
+				{
+					type: "test-component-one",
+					component_class_id: "example_class_id",
+					id: 1,
+					props: {
+						value: "hi",
+						interactive: false
+					},
+					has_modes: false,
+					instance: {} as any,
+					component: {} as any
+				}
+			],
+			["test-component-one"]
+		);
+		expect(result.component).toBeTypeOf("object");
+		expect(result.example_components).toBeInstanceOf(Map);
+	});
+
+	test("when example components are returned, returns an object with the correct keys and values and example components", () => {
+		const result = get_component(
+			"dataset",
+			"class_id",
+			"root",
+			[
+				{
+					type: "test-component-one",
+					component_class_id: "example_class_id",
+					id: 1,
+					props: {
+						value: "hi",
+						interactive: false
+					},
+					has_modes: false,
+					instance: {} as any,
+					component: {} as any
+				}
+			],
+			["test-component-one"]
+		);
+		expect(result.example_components?.get("test-component-one")).toBeTypeOf(
+			"object"
+		);
+		expect(result.example_components?.get("test-component-one")).toBeInstanceOf(
+			Promise
+		);
+	});
+
+	test("if the component is not found then it should request the component from the server", async () => {
+		const api_url = "example.com";
+		const id = "test-random";
+		const variant = "component";
+		const handlers = [
+			http.get(`${api_url}/custom_component/${id}/${variant}/style.css`, () => {
+				return new HttpResponse('console.log("boo")', {
+					status: 200,
+					headers: {
+						"Content-Type": "text/css"
+					}
+				});
+			})
+		];
+
+		// vi.mock calls are always hoisted out of the test function to the top of the file
+		// so we need to use vi.hoisted to hoist the mock function above the vi.mock call
+		const { mock } = vi.hoisted(() => {
+			return { mock: vi.fn() };
+		});
+
+		vi.mock(
+			`example.com/custom_component/test-random/component/index.js`,
+			async () => {
+				mock();
+				return {
+					default: {
+						default: "HELLO"
+					}
+				};
+			}
+		);
+
+		const server = setupServer(...handlers);
+		server.listen();
+
+		await get_component("test-random", id, api_url, []).component;
+
+		expect(mock).toHaveBeenCalled();
+
+		server.close();
+	});
+});
diff --git a/js/app/test/test_chatinterface_streaming_echo.spec.ts b/js/app/test/test_chatinterface_streaming_echo.spec.ts
--- a/js/app/test/test_chatinterface_streaming_echo.spec.ts
+++ b/js/app/test/test_chatinterface_streaming_echo.spec.ts
@@ -42,7 +42,6 @@ test("chatinterface works with streaming functions and all buttons behave as exp
 	const expected_text_el_2 = page.locator(".bot p", {
 		hasText: "Run 3 - You typed: hello"
 	});
-	expect(textbox).toHaveValue("");
 	await expect(expected_text_el_2).toBeVisible();
 
 	await expect