@ribajs/core
Version:
Core module of Riba.js
809 lines • 78.8 kB
JavaScript
import { jest } from '@jest/globals';
import { Riba, Binder } from "./index.js";
import { Data } from "../spec/lib/moch.data.js";
import { dotAdapter } from "./adapters/index.js";
import { TextBinder, HtmlBinder, EachStarBinder, ValueBinder, AddClassBinder, } from "./binders/index.js";
describe("riba.Binder", () => {
const riba = new Riba();
riba.module.adapter.register(dotAdapter);
riba.module.binder.register(TextBinder);
riba.module.binder.register(HtmlBinder);
riba.module.binder.register(ValueBinder);
riba.module.binder.register(EachStarBinder);
riba.module.binder.register(AddClassBinder);
let model;
let el;
let view;
let binding;
let originalPrefix;
let adapter;
let routineFn;
beforeEach(() => {
originalPrefix = riba.prefix;
riba.prefix = ["data"];
adapter = riba.adapters["."];
el = document.createElement("div");
el.setAttribute("data-text", "obj.name");
view = riba.bind(el, { obj: { name: "test" } });
binding = view.bindings[0];
model = binding.model;
});
afterEach(() => {
riba.prefix = originalPrefix;
});
it("gets assigned the proper binder routine matching the identifier", () => {
routineFn = binding.name;
expect(routineFn).toEqual("text");
expect(routineFn).toEqual(riba.binders.text.key);
});
describe("when bind to non configurable properties", () => {
let data;
beforeEach(() => {
data = {
name: "x",
items: [],
};
Object.defineProperty(data, "name", {
enumerable: true,
configurable: false,
writable: true,
value: "y",
});
el.setAttribute("data-show", "obj.items.length");
});
it("does not throw", () => {
expect(() => {
riba.bind(el, { obj: data });
}).not.toThrow();
});
});
describe("with multiple prefixes", () => {
beforeEach(() => {
riba.prefix = ["foo", "bar", "any"];
el.setAttribute("foo-a", "'a'");
el.setAttribute("bar-b", "'b'");
el.setAttribute("any-c", "'c'");
el.setAttribute("rv-d", "'d'");
});
it("All prefixes should be applied", () => {
expect(() => {
riba.bind(el, {});
}).not.toThrow();
expect(el.getAttribute("a")).toEqual("a");
expect(el.getAttribute("b")).toEqual("b");
expect(el.getAttribute("c")).toEqual("c");
expect(el.getAttribute("d")).toBeNull();
});
});
describe("with formatters", () => {
let valueInput;
beforeEach(() => {
const awesomeFormatter = {
name: "awesome",
read: (value) => "awesome " + value,
};
const totallyFormatter = {
name: "totally",
read: (value, prefix) => prefix + " totally " + value,
};
const placeholderFormatter = {
name: "and",
read: (value, affix) => value + affix,
};
riba.module.formatter.register(awesomeFormatter);
riba.module.formatter.register(totallyFormatter);
riba.module.formatter.register(placeholderFormatter, "and", true);
riba.module.formatter.register(placeholderFormatter, "radical", true);
riba.module.formatter.register(placeholderFormatter, "totally", true);
});
it("register all formatters", () => {
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", "obj.name | awesome | radical | totally");
view = riba.bind(valueInput, { obj: { name: "nothing" } });
binding = view.bindings[0];
expect(binding.formatters).toEqual(["awesome", "radical", "totally"]);
});
it("allows arguments with pipes", () => {
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", `obj.name | awesome | totally 'arg | with || pipes' 'and more args' | and 'others formatters' with 'pi||pes'`);
view = riba.bind(valueInput, { obj: { name: "nothing" } });
binding = view.bindings[0];
expect(binding.formatters).toEqual([
"awesome",
`totally 'arg | with || pipes' 'and more args'`,
`and 'others formatters' with 'pi||pes'`,
]);
});
});
describe("bind()", () => {
it("subscribes to the model for changes via the adapter", () => {
jest.spyOn(adapter, "observe");
binding._bind();
expect(adapter.observe).toHaveBeenCalledWith(model, "name", binding);
});
it(`calls the binder's bind method if one exists`, () => {
expect(() => {
binding._bind();
}).not.toThrow();
binding.bind = () => {
return;
};
jest.spyOn(binding, "bind");
binding._bind();
expect(binding.bind).toHaveBeenCalled();
});
describe("with preloadData set to true", () => {
beforeEach(() => {
riba.preloadData = true;
});
it("sets the initial value", () => {
jest.spyOn(binding, "set");
binding._bind();
expect(binding.set).toHaveBeenCalledWith("test");
});
});
});
describe("unbind()", () => {
describe("without a binder.unbind defined", () => {
it("should not throw an error", () => {
expect(() => {
binding._unbind();
}).not.toThrow();
});
});
describe("with a binder.unbind defined", () => {
beforeEach(() => {
binding.unbind = () => {
};
});
it("should not throw an error", () => {
expect(() => {
binding._unbind();
}).not.toThrow();
});
it(`calls the binder's unbind method`, () => {
jest.spyOn(binding, "unbind");
binding._unbind();
expect(binding.unbind).toHaveBeenCalled();
});
});
});
describe("set()", () => {
it("performs the binding routine with the supplied value", () => {
routineFn = jest.spyOn(binding, "routine");
binding.set("sweater");
expect(routineFn).toHaveBeenCalledWith(el, "sweater");
});
it("applies any formatters to the value before performing the routine", () => {
if (!view.options.formatters) {
throw new Error("formatters are undefined!");
}
routineFn = jest.spyOn(binding, "routine");
view.options.formatters.awesome = {
name: "awesome",
read(value) {
return "awesome " + value;
},
};
if (binding.formatters) {
binding.formatters.push("awesome");
}
binding.set("sweater");
expect(binding.routine).toHaveBeenCalledWith(el, "awesome sweater");
});
});
describe("publish()", () => {
let numberInput;
it(`should publish the value of a number input`, () => {
numberInput = document.createElement("input");
numberInput.setAttribute("type", "number");
numberInput.setAttribute("data-value", "obj.num");
view = riba.bind(numberInput, { obj: { num: 42 } });
binding = view.bindings[0];
model = binding.model;
numberInput.value = "42";
jest.spyOn(adapter, "set");
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "num", "42");
});
});
describe("publishTwoWay()", () => {
let numberInput;
let valueInput;
it("applies a two-way read formatter to function same as a single-way", () => {
const awesomeFormatter = {
read: (value) => "awesome " + value,
};
riba.module.formatter.register(awesomeFormatter, "awesome");
routineFn = jest.spyOn(binding, "routine");
if (!binding.formatters) {
throw new Error("Formatters not set!");
}
binding.formatters.push("awesome");
binding.set("sweater");
expect(routineFn).toHaveBeenCalledWith(el, "awesome sweater");
});
it(`should publish the value of a number input`, () => {
riba.formatters.awesome = {
publish: (value) => "awesome " + value,
};
numberInput = document.createElement("input");
numberInput.setAttribute("type", "number");
numberInput.setAttribute("data-value", "obj.num | awesome");
view = riba.bind(numberInput, { obj: { num: 42 } });
binding = view.bindings[0];
model = binding.model;
numberInput.value = "42";
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "num", "awesome 42");
});
it(`should format a value in both directions`, () => {
riba.formatters.awesome = {
publish: (value) => "awesome " + value,
read: (value) => value + " is awesome",
};
jest.spyOn(binding, "routine");
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", "obj.name | awesome");
view = riba.bind(valueInput, { obj: { name: "nothing" } });
binding = view.bindings[0];
model = binding.model;
jest.spyOn(binding, "routine");
valueInput.value = "charles";
binding.publish();
expect(binding.name).toEqual("value");
expect(adapter.set).toHaveBeenCalledWith(model, "name", "awesome charles");
binding.set("fred");
expect(binding.routine).toHaveBeenCalledWith(valueInput, "fred is awesome");
});
it(`should resolve formatter arguments to their values`, () => {
riba.formatters.withArguments = {
name: "withArguments",
publish: (value, arg1, arg2) => {
return value + ":" + arg1 + ":" + arg2;
},
read: (value, arg1, arg2) => {
return value.replace(":" + arg1 + ":" + arg2, "");
},
};
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", `obj.name | withArguments config.age 'male'`);
view = riba.bind(valueInput, {
obj: {
name: "nothing",
},
config: {
age: 50,
},
});
binding = view.bindings[0];
jest.spyOn(binding, "routine");
model = binding.model;
expect(binding.name).toEqual("value");
valueInput.value = "bobby";
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "name", "bobby:50:male");
expect(valueInput.value).toEqual("bobby");
binding.set("andy:50:male");
expect(binding.routine).toHaveBeenCalledWith(valueInput, "andy");
});
it(`should resolve formatter arguments correctly with multiple formatters`, () => {
riba.formatters.wrap = {
name: "wrap",
publish: (value, arg1, arg2) => {
return arg1 + value + arg2;
},
read: (value, arg1, arg2) => {
return value.replace(arg1, "").replace(arg2, "");
},
};
riba.formatters.saveAsCase = {
name: "saveAsCase",
publish: (value, typeCase) => {
return value["to" + typeCase + "Case"]();
},
read: (value, typeCase) => {
return value[typeCase === "Upper" ? "toLowerCase" : "toUpperCase"]();
},
};
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", `obj.name | saveAsCase config.typeCase | wrap config.curly '}' | wrap config.square ']' | wrap config.paren ')'`);
view = riba.bind(valueInput, {
obj: {
name: "nothing",
},
config: {
paren: "(",
square: "[",
curly: "{",
typeCase: "Upper",
},
});
binding = view.bindings[0];
model = binding.model;
jest.spyOn(binding, "routine");
valueInput.value = "bobby";
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "name", "{[(BOBBY)]}");
expect(valueInput.value).toEqual("bobby");
binding.set("{[(ANDY)]}");
expect(binding.routine).toHaveBeenCalledWith(valueInput, "andy");
});
it(`should not fail or format if the specified binding function doesn't exist`, () => {
riba.formatters.awesome = {};
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", "obj.name | awesome");
view = riba.bind(valueInput, { obj: { name: "nothing" } });
binding = view.bindings[0];
model = binding.model;
jest.spyOn(binding, "routine");
valueInput.value = "charles";
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "name", "charles");
binding.set("fred");
expect(binding.routine).toHaveBeenCalledWith(valueInput, "fred");
});
it(`should apply read binders left to right, and write binders right to left`, () => {
riba.formatters.totally = {
name: "totally",
publish: (value) => value + " totally",
read: (value) => value + " totally",
};
riba.formatters.awesome = {
name: "awesome",
publish: (value) => value + " is awesome",
read: (value) => value + " is awesome",
};
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", "obj.name | awesome | totally");
view = riba.bind(valueInput, { obj: { name: "nothing" } });
binding = view.bindings[0];
model = binding.model;
jest.spyOn(binding, "routine");
binding.set("fred");
expect(binding.routine).toHaveBeenCalledWith(valueInput, "fred is awesome totally");
valueInput.value = "fred";
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "name", "fred totally is awesome");
});
it(`binders in a chain should be skipped if they're not there`, () => {
riba.formatters.totally = {
name: "totally",
publish: (value) => value + " totally",
read: (value) => value + " totally",
};
riba.formatters.radical = {
name: "radical",
publish: (value) => value + " is radical",
};
riba.formatters.awesome = {
name: "awesome",
read: (value) => value + " is awesome",
};
valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("data-value", "obj.name | awesome | radical | totally");
view = riba.bind(valueInput, { obj: { name: "nothing" } });
binding = view.bindings[0];
jest.spyOn(binding, "routine");
expect(binding.name).toEqual("value");
model = binding.model;
binding.set("fred");
expect(binding.routine).toHaveBeenCalledWith(valueInput, "fred is awesome totally");
valueInput.value = "fred";
binding.publish();
expect(adapter.set).toHaveBeenCalledWith(model, "name", "fred totally is radical");
});
});
describe("formattedValue()", () => {
it("applies the current formatters on the supplied value", () => {
if (!view.options.formatters) {
throw new Error("formatters are undefined!");
}
view.options.formatters.awesome = {
name: "awesome",
read(value) {
return "awesome " + value;
},
};
if (!binding.formatters) {
throw new Error("Formatters not set!");
}
binding.formatters.push("awesome");
expect(binding.formattedValue("hat")).toEqual("awesome hat");
});
describe("with a multi-argument formatter string", () => {
beforeEach(() => {
if (!view.options.formatters) {
throw new Error("formatters are undefined!");
}
view.options.formatters.awesome = {
name: "awesome",
read(value, prefix) {
return prefix + " awesome " + value;
},
};
if (!binding.formatters) {
throw new Error("Formatters not set!");
}
binding.formatters.push(`awesome 'super'`);
});
it("applies the formatter with arguments", () => {
expect(binding.formattedValue("jacket")).toEqual("super awesome jacket");
});
});
describe("with a formatter string with pipes in argument", () => {
beforeEach(() => {
if (!view.options.formatters) {
throw new Error("formatters are undefined!");
}
view.options.formatters.totally = {
name: "totally",
read(value, prefix) {
return prefix + " totally " + value;
},
};
if (!binding.formatters) {
throw new Error("Formatters not set!");
}
binding.formatters.push(`totally 'arg | with || pipes'`);
});
it("applies the formatter with arguments with pipes", () => {
expect(binding.formattedValue("jacket")).toEqual("arg | with || pipes totally jacket");
});
});
});
describe("getValue()", () => {
it("should use binder.getValue() if present", () => {
binding.getValue = () => {
return "foo";
};
expect(binding._getValue(el)).toEqual("foo");
});
it("binder.getValue() should have access to passed element", () => {
binding.getValue = (_el) => {
return _el.dataset.foo;
};
el.dataset.foo = "bar";
expect(binding._getValue(el)).toEqual("bar");
});
it("binder.getValue() should have access to binding", () => {
binding.getValue = function () {
return this.foo;
};
binding.foo = "bar";
expect(binding._getValue(el)).toEqual("bar");
});
});
});
describe("Functional", () => {
const riba = new Riba();
riba.module.adapter.register(dotAdapter);
riba.module.binder.register(TextBinder);
riba.module.binder.register(HtmlBinder);
riba.module.binder.register(ValueBinder);
riba.module.binder.register(EachStarBinder);
riba.module.binder.register(AddClassBinder);
let data;
let bindData;
let el;
let input;
let originalPrefix;
let adapter;
beforeEach(() => {
originalPrefix = riba.prefix;
riba.prefix = ["data"];
adapter = {
name: ":",
observe: (obj, keypath, callback) => {
obj.on(keypath, callback);
},
unobserve: (obj, keypath, callback) => {
obj.off(keypath, callback);
},
get: (obj, keypath) => {
return obj.get(keypath);
},
set: (obj, keypath, value) => {
const attributes = {};
attributes[keypath] = value;
obj.set(attributes);
},
};
riba.module.adapter.register(adapter);
riba.configure({ preloadData: true });
data = new Data({
foo: "bar",
items: [{ name: "a" }, { name: "b" }],
});
bindData = { data };
el = document.createElement("div");
el.setAttribute("rv-value", "");
input = document.createElement("input");
input.setAttribute("type", "text");
});
afterEach(() => {
riba.prefix = originalPrefix;
});
describe("Binds", () => {
describe("Text", () => {
it("should set the text content of the element", () => {
el.setAttribute("data-text", "data:foo");
riba.bind(el, bindData);
expect(el.textContent).toEqual(data.get("foo"));
});
it("should correctly handle HTML in the content", () => {
el.setAttribute("data-text", "data:foo");
const value = "<b>Fail</b>";
data.set({ foo: value });
riba.bind(el, bindData);
expect(el.textContent).toEqual(value);
});
});
describe("HTML", () => {
it("should set the html content of the element", () => {
el.setAttribute("data-html", "data:foo");
riba.bind(el, bindData);
expect(el.textContent).toEqual(data.get("foo"));
});
it("should correctly handle HTML in the content", () => {
el.setAttribute("data-html", "data:foo");
const value = "<b>Fail</b>";
data.set({ foo: value });
riba.bind(el, bindData);
expect(el.innerHTML).toEqual(value);
});
});
describe("Value", () => {
it("should set the value of the element", () => {
input.setAttribute("data-value", "data:foo");
riba.bind(input, bindData);
expect(input.value).toEqual(data.get("foo"));
});
});
describe("Multiple", () => {
it("should bind a list of multiple elements", () => {
el.setAttribute("data-html", "data:foo");
input.setAttribute("data-value", "data:foo");
riba.bind([el, input], bindData);
expect(el.textContent).toEqual(data.get("foo"));
expect(input.value).toEqual(data.get("foo"));
});
});
describe("Priority", () => {
let mockA;
let mockB;
let mockC;
let mockD;
let mockE;
let mockF;
let mockG;
beforeEach(() => {
mockA = jest.fn();
mockB = jest.fn();
mockC = jest.fn();
mockD = jest.fn();
mockE = jest.fn();
mockF = jest.fn();
mockG = jest.fn();
class ABinder extends Binder {
static key = "a";
bind = mockA;
routine() {
}
}
class BBinder extends Binder {
static key = "b";
bind = mockB;
routine() {
}
}
class CBinder extends Binder {
static key = "c";
priority = 10;
bind = mockC;
routine() {
}
}
class DBinder extends Binder {
static key = "d";
priority = 30;
bind = mockD;
routine() {
}
}
class EBinder extends Binder {
static key = "e";
priority = 5;
bind = mockE;
routine() {
}
}
class FBinder extends Binder {
static key = "f";
priority = 2;
bind = mockF;
routine() {
}
}
class GBinder extends Binder {
static key = "g";
priority = 1;
bind = mockG;
routine() {
}
}
riba.module.binder.register(ABinder);
riba.module.binder.register(BBinder);
riba.module.binder.register(CBinder);
riba.module.binder.register(DBinder);
riba.module.binder.register(EBinder);
riba.module.binder.register(FBinder);
riba.module.binder.register(GBinder);
el.setAttribute("data-a", "data:foo");
el.setAttribute("data-b", "data:foo");
el.setAttribute("data-c", "data:foo");
el.setAttribute("data-d", "data:foo");
el.setAttribute("data-e", "data:foo");
el.setAttribute("data-f", "data:foo");
el.setAttribute("data-g", "data:foo");
});
describe("a:10, b:30", () => {
beforeEach(() => {
const view = riba.bind(el, bindData);
const c = view.bindings[1];
const d = view.bindings[0];
expect(c.name).toEqual("c");
expect(c.priority).toEqual(10);
expect(d.name).toEqual("d");
expect(d.priority).toEqual(30);
});
it("should bind d before c", () => {
expect(mockD).toHaveBeenCalledBefore(mockC);
});
});
describe("a:5, b:2", () => {
beforeEach(() => {
const view = riba.bind(el, bindData);
const e = view.bindings[2];
const f = view.bindings[3];
expect(e.name).toEqual("e");
expect(e.priority).toEqual(5);
expect(f.name).toEqual("f");
expect(f.priority).toEqual(2);
});
it("should bind e before f", () => {
expect(mockE).toHaveBeenCalledBefore(mockF);
});
});
describe("a:undefined, g:1", () => {
beforeEach(() => {
const view = riba.bind(el, bindData);
const g = view.bindings[4];
expect(g.name).toEqual("g");
expect(g.priority).toEqual(1);
riba.bind(el, bindData);
});
it("should bind g before a", () => {
expect(mockG).toHaveBeenCalledBefore(mockA);
});
});
});
describe("Iteration", () => {
let listItem;
let list;
beforeEach(() => {
list = document.createElement("ul");
el.appendChild(list);
listItem = document.createElement("li");
listItem.setAttribute("data-each-item", "data:items");
list.appendChild(listItem);
});
it("should loop over a collection and create new instances of that element + children", () => {
expect(el.getElementsByTagName("li").length).toEqual(1);
riba.bind(el, bindData);
expect(el.getElementsByTagName("li").length).toEqual(2);
});
it("should not fail if the collection being bound to is null", () => {
data.set({ items: null });
riba.bind(el, bindData);
expect(el.getElementsByTagName("li").length).toEqual(0);
});
it("should re-loop over the collection and create new instances when the array changes", () => {
riba.bind(el, bindData);
expect(el.getElementsByTagName("li").length).toEqual(2);
const newItems = [{ name: "a" }, { name: "b" }, { name: "c" }];
data.set({ items: newItems });
expect(el.getElementsByTagName("li").length).toEqual(3);
});
it("should allow binding to the iterated item as well as any parent contexts", () => {
const span1 = document.createElement("span");
span1.setAttribute("data-text", "item.name");
const span2 = document.createElement("span");
span2.setAttribute("data-text", "data:foo");
listItem.appendChild(span1);
listItem.appendChild(span2);
riba.bind(el, bindData);
expect(el.getElementsByTagName("span")[0].textContent).toEqual("a");
expect(el.getElementsByTagName("span")[1].textContent).toEqual("bar");
});
it("should allow binding to the iterated element directly", () => {
listItem.setAttribute("data-text", "item.name");
listItem.setAttribute("data-add-class", "data:foo");
riba.bind(el, bindData);
expect(el.getElementsByTagName("li")[0].textContent).toEqual("a");
expect(el.getElementsByTagName("li")[0].className).toEqual("bar");
});
it("should insert items between any surrounding elements", () => {
const firstItem = document.createElement("li");
const lastItem = document.createElement("li");
firstItem.textContent = "first";
lastItem.textContent = "last";
list.appendChild(lastItem);
list.insertBefore(firstItem, listItem);
listItem.setAttribute("data-text", "item.name");
riba.bind(el, bindData);
expect(el.getElementsByTagName("li")[0].textContent).toEqual("first");
expect(el.getElementsByTagName("li")[1].textContent).toEqual("a");
expect(el.getElementsByTagName("li")[2].textContent).toEqual("b");
expect(el.getElementsByTagName("li")[3].textContent).toEqual("last");
});
it.skip("should allow binding to the iterated element index", () => {
listItem.setAttribute("data-index", "%item%");
riba.bind(el, bindData);
expect(el.getElementsByTagName("li")[0].getAttribute("index")).toEqual("0");
expect(el.getElementsByTagName("li")[1].getAttribute("index")).toEqual("1");
});
it.skip("should allow the developer to configure the index attribute available in the iteration", () => {
listItem.setAttribute("data-index", "itemIndex");
listItem.setAttribute("index-property", "itemIndex");
riba.bind(el, bindData);
expect(el.outerHTML).toEqual("");
expect(el.getElementsByTagName("li")[0].getAttribute("index")).toEqual("0");
expect(el.getElementsByTagName("li")[1].getAttribute("index")).toEqual("1");
});
});
});
describe("Updates", () => {
it("should change the value", () => {
el.setAttribute("data-text", "data:foo");
riba.bind(el, bindData);
data.set({ foo: "some new value" });
expect(el.textContent).toEqual(data.get("foo"));
});
});
describe("Input", () => {
it("should update the model value", () => {
input.setAttribute("data-value", "data:foo");
riba.bind(input, bindData);
input.value = "some new value";
const event = document.createEvent("HTMLEvents");
event.initEvent("input", true, true);
input.dispatchEvent(event);
expect(data.get("foo")).toEqual("some new value");
});
it("should allow to change the event listened", () => {
let event;
input.setAttribute("data-value", "data:foo");
input.setAttribute("event-name", "blur");
riba.bind(input, bindData);
input.value = "some new value";
event = document.createEvent("HTMLEvents");
event.initEvent("input", true, true);
input.dispatchEvent(event);
expect(data.get("foo")).toEqual("bar");
event = document.createEvent("HTMLEvents");
event.initEvent("blur", true, true);
input.dispatchEvent(event);
expect(data.get("foo")).toEqual("some new value");
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmluZGVyLnNwZWMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYmluZGVyLnNwZWMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyQyxPQUFPLEVBQUUsSUFBSSxFQUFRLE1BQU0sRUFBRSxNQUFNLFlBQVksQ0FBQztBQUNoRCxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2pELE9BQU8sRUFDTCxVQUFVLEVBQ1YsVUFBVSxFQUNWLGNBQWMsRUFDZCxXQUFXLEVBQ1gsY0FBYyxHQUNmLE1BQU0sb0JBQW9CLENBQUM7QUFHNUIsUUFBUSxDQUFDLGFBQWEsRUFBRSxHQUFHLEVBQUU7SUFDM0IsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztJQUN4QixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDekMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3hDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDekMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzVDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUU1QyxJQUFJLEtBQWEsQ0FBQztJQUNsQixJQUFJLEVBQWUsQ0FBQztJQUNwQixJQUFJLElBQVUsQ0FBQztJQUNmLElBQUksT0FBaUMsQ0FB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