UNPKG

@ribajs/core

Version:

Core module of Riba.js

272 lines (235 loc) 8.61 kB
import { vi } from 'vitest'; import { Riba } from "../riba.js"; import { dotAdapter } from "../adapters/dot.adapter.js"; import { ValueBinder } from "./value.binder.js"; import { Adapters } from "../types/index.js"; describe("riba.binders", () => { describe("value", () => { const riba = new Riba(); riba.module.adapter.register(dotAdapter); riba.module.binder.register(ValueBinder); let fragment: DocumentFragment; let el: HTMLInputElement; let model: any; beforeEach(() => { model = { value: "foobar" }; fragment = document.createDocumentFragment(); el = document.createElement("input"); el.setAttribute("rv-value", "value"); fragment.appendChild(el); }); it("unbinds the same bound function", () => { let boundFn: EventListenerOrEventListenerObject; vi.spyOn(el, "addEventListener").mockImplementation((event, fn) => { boundFn = fn; }); const view = riba.bind(fragment, model); vi.spyOn(el, "removeEventListener").mockImplementation((event, fn) => { expect(fn).toEqual(boundFn); }); view.unbind(); }); it("binds to the model to input", () => { riba.bind(fragment, model); expect(el.value).toBe(model.value); }); it("reflects changes to the model into the DOM", () => { riba.bind(fragment, model); expect(el.value).toBe("foobar"); model.value = "howdy"; expect(el.value).toBe("howdy"); }); it("reflects changes to the model into the DOM after unbind/bind", () => { const view = riba.bind(fragment, model); expect(el.value).toBe("foobar"); view.unbind(); view.bind(); model.value = "howdy"; expect(el.value).toBe("howdy"); }); }); describe("value", () => { let input: HTMLInputElement; const riba = new Riba(); let fragment: DocumentFragment; let model: any; const createOptionEls = (val: string) => { const option = document.createElement("option"); option.value = val; option.textContent = val + " text"; return option; }; const createSelectElement = ( isMultiple: boolean, optionValues: Array<string> | { [group: string]: Array<string> } ) => { const elem = document.createElement("select"); let options = new Array<any>(); if (Array.isArray(optionValues)) { options = optionValues.map(createOptionEls); options.forEach((option) => { elem.appendChild(option); }); } else { // grouped Object.keys(optionValues).forEach((group) => { const optGroupEl = document.createElement("optgroup"); optGroupEl.label = group; options = optionValues[group].map(createOptionEls); options.forEach((option) => { optGroupEl.appendChild(option); }); elem.appendChild(optGroupEl); }); } if (isMultiple) { elem.multiple = true; } document.body.appendChild(elem); return elem; }; const createInputElement = (type: string, value?: string) => { const elem = document.createElement("input"); elem.setAttribute("type", type); if (value !== undefined) { elem.setAttribute("value", value); } document.body.appendChild(elem); return elem; }; beforeEach(() => { riba.module.binder.register(ValueBinder); riba.configure({ adapters: { subscribe: () => { /**/ }, unsubscribe: () => { /**/ }, read: () => { /**/ }, publish: () => { /**/ }, } as unknown as Adapters, }); input = createInputElement("text"); model = { value: "foobar" }; fragment = document.createDocumentFragment(); const el = document.createElement("div"); el.setAttribute("rv-value", ""); fragment.appendChild(el); }); afterEach(() => { if (!input.parentNode) { throw new Error("input.parentNode is not defined!"); } input.parentNode.removeChild(input); }); it("sets the element's value", () => { const view = riba.bind(fragment, model); const valueBinder = view.bindings[0] as ValueBinder; expect(valueBinder.name).toEqual("value"); valueBinder.routine(input, "pitchfork"); expect(input.value).toEqual("pitchfork"); }); it("applies a default value to the element when the model doesn't contain it", () => { const view = riba.bind(fragment, model); const valueBinder = view.bindings[0] as ValueBinder; expect(valueBinder.name).toEqual("value"); valueBinder.routine(input, undefined); expect(input.value).toEqual(""); }); it("sets the element's value to zero when a zero value is passed", () => { const view = riba.bind(fragment, model); expect(view.bindings).toHaveLength(1); const valueBinder = view.bindings[0] as ValueBinder; expect(valueBinder.name).toEqual("value"); valueBinder.routine(input, 0); expect(input.value).toEqual("0"); }); describe("in a select element", () => { let selectEl: HTMLSelectElement; let selectMultipleEl: HTMLSelectElement; let groupedSelectEl: HTMLSelectElement; let groupedMultipleSelectEl: HTMLSelectElement; beforeEach(() => { selectEl = createSelectElement(false, ["a", "b", "c"]); selectMultipleEl = createSelectElement(true, ["d", "e", "f"]); groupedSelectEl = createSelectElement(false, { group1: ["a"], group2: ["b", "c"], }); groupedMultipleSelectEl = createSelectElement(true, { group1: ["a"], group2: ["b", "c"], }); }); it("sets the correct option on a select element", () => { const view = riba.bind(fragment, model); const valueBinder = view.bindings[0] as ValueBinder; valueBinder.routine(selectEl, "b"); valueBinder.routine(selectEl, "c"); expect(selectEl.value).toEqual("c"); }); it("sets the correct option on a select-multiple element", () => { const view = riba.bind(fragment, model); const valueBinder = view.bindings[0] as ValueBinder; valueBinder.routine(selectMultipleEl, ["d", "f"]); const result = Array.prototype.slice .call(selectMultipleEl.children) .filter((option: any) => { return option.selected; }) .map((option: any) => { return option.value; }); expect(result).toEqual(["d", "f"]); }); it("sets the correct option on a grouped select element", () => { const view = riba.bind(fragment, model); const valueBinder = view.bindings[0] as ValueBinder; valueBinder.routine(groupedSelectEl, "b"); valueBinder.routine(groupedSelectEl, "c"); expect(groupedSelectEl.value).toEqual("c"); }); it("sets the correct option on a select-multiple element", () => { const view = riba.bind(fragment, model); const valueBinder = view.bindings[0] as ValueBinder; expect(view.bindings).toHaveLength(1); expect(valueBinder).toBeDefined(); expect(valueBinder.name).toEqual("value"); valueBinder.routine(groupedMultipleSelectEl, ["a", "c"]); const result = Array.prototype.slice .call(groupedMultipleSelectEl.options) .filter((option: any) => { return option.selected; }) .map((option: any) => { return option.value; }); expect(result).toEqual(["a", "c"]); }); afterEach(() => { if (!selectEl.parentNode) { throw new Error("selectEl.parentNode is not defined!"); } if (!selectMultipleEl.parentNode) { throw new Error("selectMultipleEl.parentNode is not defined!"); } if (!groupedSelectEl.parentNode) { throw new Error("groupedSelectEl.parentNode is not defined!"); } if (!groupedMultipleSelectEl.parentNode) { throw new Error("groupedMultipleSelectEl.parentNode is not defined!"); } selectEl.parentNode.removeChild(selectEl); selectMultipleEl.parentNode.removeChild(selectMultipleEl); groupedSelectEl.parentNode.removeChild(groupedSelectEl); groupedMultipleSelectEl.parentNode.removeChild(groupedMultipleSelectEl); }); }); }); });