//// A module for initializing tests and rendering components. \ //// Use it in combination with `novdom_testing/component_should` to test novdom components. import novdom/hotkey import novdom/internals/component.{type Component} as internal_component import novdom/internals/parameter.{type Event, type Parameter, Listener} import novdom/parameter/motion /// A type to check if a function was called. pub opaque type Callee { Callee(id: String) } /// A Type for a function that creates a parameter with a listener (e.g. `onclick`). pub type ParameterFn = fn(fn(Event) -> Nil) -> Parameter /// Initialize the testing environment. This function should be called at the beginning of a test. pub fn init(test_fn: fn() -> a) -> Nil { init_js() test_fn() Nil } /// Render a component in the viewport. This function should be called in a test function. \ /// **Warning:** Never use `novdom.start()` in a test function, this can lead to unexpected behavior. pub fn render(component: fn() -> Component) -> Nil { // TODO: Move to init()?? motion.init() hotkey.init() component() |> internal_component.add_to_viewport() // wait(5) } /// Create a callee type that can be used to test if a function was called pub fn create_callee() -> Callee { create_callee_js() |> Callee } /// Call a callee to later check if it was called (see `callee_count`). /// Use this function to simulate a function call. pub fn call_callee(callee: Callee) { call_callee_js(callee.id) } /// Check how often a callee was called pub fn callee_count(callee: Callee) -> Int { callee_count_js(callee.id) } /// Trigger an event on a component. /// /// Example for a click event: /// ```gleam /// trigger_event(my_component, onclick) /// ``` /// pub fn trigger_event(component: Component, listener: ParameterFn) -> Component { let assert Listener(name, _) = listener(fn(_) { Nil }) trigger_event_js(component, name) component } /// Name a step in a test to make error messages more precise. This does only work with `novdom_testing/component_should` functions (not with `gleeunit/should`). /// /// Example: /// ```gleam /// comp /// |> step("Check if component is visible") /// |> component_should.be_visible() /// ``` /// pub fn step(subject: a, step: String) -> a { set_step(step) subject } /// Gets all children of a component. pub fn children(component: Component) -> List(Component) { internal_component.children(component) } /// Gets a specific child of a component. pub fn child(component: Component, index: Int) -> Result(Component, Nil) { internal_component.child(component, index) } /// Set a description for a component to be used in error messages @external(javascript, "../testing_ffi.mjs", "set_description") pub fn description(component: Component, desc: String) -> Component /// Trigger the `onreplacement` modifier on a component. @external(javascript, "../testing_ffi.mjs", "trigger_unrender") pub fn trigger_replacement(component: Component) -> Component @external(javascript, "../testing_ffi.mjs", "current_step") fn set_step(step: String) -> Nil @external(javascript, "../testing_ffi.mjs", "trigger_event") fn trigger_event_js(component: Component, event: String) -> Nil @external(javascript, "../testing_ffi.mjs", "create_callee") fn create_callee_js() -> String @external(javascript, "../testing_ffi.mjs", "call_callee") fn call_callee_js(id: String) -> Nil @external(javascript, "../testing_ffi.mjs", "callee_count") fn callee_count_js(id: String) -> Int @external(javascript, "../testing_ffi.mjs", "init") fn init_js() -> Nil