describe("Data Model Updates", () => {
it("should update data at a specified path", () => {
processor.processMessages([
{
dataModelUpdate: {
surfaceId: "@default",
path: "/user",
contents: [{ key: "name", valueString: "Alice" }],
},
},
]); const name = processor.getData(
{ dataContextPath: "/" } as v0_8.Types.AnyComponentNode, "/user/name"
); assert.strictEqual(name, "Alice");
});
it("should replace the entire data model when path is not provided", () => {
processor.processMessages([
{
dataModelUpdate: {
surfaceId: "@default",
path: "/",
contents: [
{ key: "user", valueString: JSON.stringify({ name: "Bob" }) },
],
},
},
]); const user = processor.getData(
{ dataContextPath: "/" } as v0_8.Types.AnyComponentNode, "/user"
); assert.deepStrictEqual(toPlainObject(user), { name: "Bob" });
});
it("should create nested structures when setting data", () => { const component = { dataContextPath: "/" } as v0_8.Types.AnyComponentNode; // Note: setData is a public method that does not use the key-value format
processor.setData(component, "/a/b/c", "value"); const data = processor.getData(component, "/a/b/c"); assert.strictEqual(data, "value");
});
const info = processor.getData(
{ dataContextPath: "/" } as v0_8.Types.AnyComponentNode, "/data/users"
);
// The expected result is a Map of Maps. const expected = new Map([
[ "user1", new Map([
["firstName", "Alice"],
["lastName", "Doe"],
]),
],
[ "user2", new Map([
["firstName", "John"],
["lastName", "Doe"],
]),
],
]);
assert.deepEqual(info, expected);
});
it("should additively update a Map using numeric-string keys (like timestamps)", () => { // 1. First, establish the /messages path as a Map.
processor.processMessages([
{
dataModelUpdate: {
surfaceId: "@default",
path: "/messages",
contents: [ // Sending an empty key-value array creates an empty Map at the path.
],
},
},
]);
let messagesData = processor.getData(
{ dataContextPath: "/" } as v0_8.Types.AnyComponentNode, "/messages"
);
// Check that it's a Map and has the first item.
assertIsDataMap(messagesData); assert.strictEqual(messagesData.size, 1); assert.strictEqual(messagesData.get(key1), message1);
// 3. Add the second message. This is where the old logic would fail.
processor.processMessages([
{
dataModelUpdate: {
surfaceId: "@default",
path: `/messages/${key2}`,
contents: [
{
key: ".",
valueString: message2,
},
],
},
},
]);
// 4. Check that the Map was additively updated and now has both items.
assertIsDataMap(messagesData); assert.strictEqual(messagesData.size, 2, "Map should have 2 items total"); assert.strictEqual(
(messagesData as DataMap).get(key1),
message1, "First item correct"
); assert.strictEqual(
messagesData.get(key2),
message2, "Second item correct"
);
});
});
// Now, try to render, which triggers the tree build assert.throws(() => {
processor.processMessages([
{
beginRendering: {
root: "a",
surfaceId: "@default",
},
},
]);
}, new Error(`Circular dependency for component "a".`));
const tree = processor.getSurfaces().get("@default")?.componentTree; assert.strictEqual(
tree, null, "Tree should be null due to circular dependency"
);
});
let tree = processor.getSurfaces().get("@default")?.componentTree; assert.strictEqual(
toPlainObject(tree).properties.children.length, 0, "Children should be empty before data arrives"
);
tree = processor.getSurfaces().get("@default")?.componentTree; assert.strictEqual(
toPlainObject(tree).properties.children.length, 2, "Children should be populated after data arrives"
);
});
it("should trim relative paths within a data context (./item)", () => {
processor.processMessages([
{
dataModelUpdate: {
surfaceId: "@default",
path: "/",
contents: [
{
key: "items",
valueString: JSON.stringify([{ name: "A" }, { name: "B" }]),
},
],
},
},
{
surfaceUpdate: {
surfaceId: "@default",
components: [
{
id: "root",
component: {
List: {
children: {
template: {
componentId: "item-template",
dataBinding: "/items",
},
},
},
},
}, // These paths would are typical when a databinding is used.
{
id: "item-template",
component: { Text: { text: { path: "./item/name" } } },
},
],
},
},
{
beginRendering: {
root: "root",
surfaceId: "@default",
},
},
]);
// The processor should have trimmed `/item` and `./` from the path // because we are inside a data context. assert.deepEqual(child1.properties.text, { path: "name" }); assert.deepEqual(child2.properties.text, { path: "name" });
});
it("should trim relative paths within a data context (./name)", () => {
processor.processMessages([
{
dataModelUpdate: {
surfaceId: "@default",
path: "/",
contents: [
{
key: "items",
valueString: JSON.stringify([{ name: "A" }, { name: "B" }]),
},
],
},
},
{
surfaceUpdate: {
surfaceId: "@default",
components: [
{
id: "root",
component: {
List: {
children: {
template: {
componentId: "item-template",
dataBinding: "/items",
},
},
},
},
}, // These paths would are typical when a databinding is used.
{
id: "item-template",
component: { Text: { text: { path: "./name" } } },
},
],
},
},
{
beginRendering: {
root: "root",
surfaceId: "@default",
},
},
]);
// The processor should have trimmed `./` from the path // because we are inside a data context. assert.deepEqual(child1.properties.text, { path: "name" }); assert.deepEqual(child2.properties.text, { path: "name" });
});
});
describe("Data Normalization and Parsing", () => {
it("should correctly handle and parse the key-value array data format at the root", () => { const messages = [
{
dataModelUpdate: {
surfaceId: "test-surface",
path: "/",
contents: [
{ key: "title", valueString: "My Title" },
{
key: "items",
valueString: '[{"id": 1}, {"id": 2}]',
},
],
},
},
];
processor.processMessages(messages); const tree = processor.getSurfaces().get("default")?.componentTree; const plainTree = toPlainObject(tree);
// 1. Find the "item-list" component (the List) const itemList = plainTree.properties.children[1]; assert.strictEqual(itemList.id, "item-list");
// 2. Check that it expanded 5 children from the Map const templateChildren = itemList.properties.children; assert.strictEqual(templateChildren.length, 5);
// 3. Check the first generated child for correct key-based ID and data context const child1 = templateChildren[0]; assert.strictEqual(child1.id, "item-card-template:item1"); assert.strictEqual(child1.dataContextPath, "/items/item1");
// 4. Go deeper to check the data binding on a nested component // Path: Card -> Row -> Column -> Heading const child1NameHeading =
child1.properties.child.properties.children[1].properties.children[0]; assert.strictEqual(child1NameHeading.id, "template-name:item1"); assert.strictEqual(child1NameHeading.dataContextPath, "/items/item1"); assert.deepStrictEqual(child1NameHeading.properties.text, {
path: "name",
});
// 5. Check the second generated child const child2 = templateChildren[1]; assert.strictEqual(child2.id, "item-card-template:item2"); assert.strictEqual(child2.dataContextPath, "/items/item2");
});
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.