2025-03-29 22:59:13 +01:00
|
|
|
import {describe, expect, it} from "vitest";
|
|
|
|
import {circular, defineModel, s} from "../src/library";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test class of an account.
|
|
|
|
*/
|
2025-06-23 20:31:34 +02:00
|
|
|
class Account {
|
2025-03-29 22:59:13 +01:00
|
|
|
static model = s.defineModel({
|
|
|
|
Class: Account,
|
|
|
|
identifier: "id",
|
|
|
|
properties: {
|
|
|
|
id: s.property.numeric(),
|
|
|
|
createdAt: s.property.date(),
|
|
|
|
name: s.property.string(),
|
|
|
|
email: s.property.string(),
|
|
|
|
active: s.property.boolean(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
id: number;
|
|
|
|
createdAt: Date;
|
|
|
|
name: string;
|
|
|
|
email: string;
|
|
|
|
active: boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test class of an article.
|
|
|
|
*/
|
2025-06-23 20:31:34 +02:00
|
|
|
class Article {
|
2025-03-29 22:59:13 +01:00
|
|
|
static model = s.defineModel({
|
|
|
|
Class: Article,
|
|
|
|
identifier: "id",
|
|
|
|
properties: {
|
|
|
|
id: s.property.numeric(),
|
|
|
|
title: s.property.string(),
|
|
|
|
authors: s.property.array(s.property.model(() => Account.model)),
|
|
|
|
text: s.property.string(),
|
|
|
|
evaluation: s.property.decimal(),
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: s.property.array(s.property.object({name: s.property.string()})),
|
2025-03-29 22:59:13 +01:00
|
|
|
comments: s.property.array(s.property.model(() => ArticleComment.model)),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
id: number;
|
|
|
|
title: string;
|
|
|
|
authors: Account[];
|
|
|
|
text: string;
|
|
|
|
evaluation: number;
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: {name: string}[];
|
2025-03-29 22:59:13 +01:00
|
|
|
comments: ArticleComment[];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test class of a comment on an article.
|
|
|
|
*/
|
2025-06-23 20:31:34 +02:00
|
|
|
class ArticleComment {
|
2025-03-29 22:59:13 +01:00
|
|
|
static model = s.defineModel({
|
|
|
|
Class: ArticleComment,
|
|
|
|
identifier: "id",
|
|
|
|
properties: {
|
|
|
|
id: s.property.numeric(),
|
|
|
|
article: s.property.model(circular<Article>(() => Article.model)),
|
|
|
|
author: s.property.model(() => Account.model),
|
|
|
|
message: s.property.string(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
id: number;
|
|
|
|
article?: Article;
|
|
|
|
author: Account;
|
|
|
|
message: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a test account instance.
|
|
|
|
*/
|
2025-06-23 20:31:34 +02:00
|
|
|
function getTestAccount(): Account {
|
2025-03-29 22:59:13 +01:00
|
|
|
const account = new Account();
|
|
|
|
account.id = 52;
|
|
|
|
account.createdAt = new Date();
|
|
|
|
account.name = "John Doe";
|
|
|
|
account.email = "john@doe.test";
|
|
|
|
account.active = true;
|
|
|
|
return account;
|
|
|
|
}
|
|
|
|
|
2025-06-23 20:31:34 +02:00
|
|
|
function getTestArticle(): Article {
|
2025-03-29 22:59:13 +01:00
|
|
|
const article = new Article();
|
|
|
|
article.id = 1;
|
|
|
|
article.title = "this is a test";
|
|
|
|
article.text = "this is a long test.";
|
|
|
|
article.evaluation = 25.23;
|
2025-06-23 20:31:34 +02:00
|
|
|
article.tags = [{name: "test"}, {name: "foo"}];
|
2025-03-29 22:59:13 +01:00
|
|
|
article.authors = [getTestAccount()];
|
|
|
|
article.comments = [];
|
|
|
|
return article;
|
|
|
|
}
|
|
|
|
|
|
|
|
describe("model", () => {
|
2025-06-22 23:25:14 +02:00
|
|
|
it("defines a new model, extending an existing one", () => {
|
2025-06-23 20:31:34 +02:00
|
|
|
class ExtendedAccount extends Account {
|
2025-06-22 23:25:14 +02:00
|
|
|
static extendedModel = s.extend(Account.model, {
|
|
|
|
Class: ExtendedAccount,
|
|
|
|
properties: {
|
|
|
|
extendedProperty: s.property.string(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
extendedProperty: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(ExtendedAccount.extendedModel.definition).toEqual({
|
|
|
|
Class: ExtendedAccount,
|
|
|
|
identifier: "id",
|
|
|
|
properties: {
|
|
|
|
id: s.property.numeric(),
|
|
|
|
createdAt: s.property.date(),
|
|
|
|
name: s.property.string(),
|
|
|
|
email: s.property.string(),
|
|
|
|
active: s.property.boolean(),
|
|
|
|
extendedProperty: s.property.string(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
it("initializes a new model", () => {
|
|
|
|
const article = getTestArticle();
|
|
|
|
const newModel = Article.model.model(article);
|
|
|
|
expect(newModel.instance).toBe(article);
|
|
|
|
});
|
|
|
|
it("gets a model state from its instance", () => {
|
|
|
|
const article = getTestArticle();
|
|
|
|
expect(Article.model.model(article).isNew()).toBeTruthy();
|
|
|
|
expect(Article.model.model(article).isDirty()).toBeFalsy();
|
|
|
|
});
|
|
|
|
it("gets a model identifier value", () => {
|
|
|
|
const article = getTestArticle();
|
|
|
|
expect(Article.model.model(article).getIdentifier()).toBe(1);
|
|
|
|
});
|
|
|
|
it("gets a model composite identifier value", () => {
|
2025-06-23 20:31:34 +02:00
|
|
|
class CompositeModel {
|
2025-03-29 22:59:13 +01:00
|
|
|
static model = s.defineModel({
|
|
|
|
Class: CompositeModel,
|
|
|
|
properties: {
|
|
|
|
firstId: s.property.numeric(),
|
|
|
|
secondId: s.property.numeric(),
|
|
|
|
label: s.property.string(),
|
|
|
|
},
|
|
|
|
identifier: ["firstId", "secondId"],
|
2025-06-23 20:31:34 +02:00
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
|
|
|
|
firstId: number;
|
|
|
|
secondId: number;
|
|
|
|
label: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
expect(
|
2025-06-23 20:31:34 +02:00
|
|
|
CompositeModel.model
|
|
|
|
.model(
|
|
|
|
Object.assign(new CompositeModel(), {
|
|
|
|
firstId: 5,
|
|
|
|
secondId: 6,
|
|
|
|
label: "test",
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.getIdentifier(),
|
2025-03-29 22:59:13 +01:00
|
|
|
).toStrictEqual([5, 6]);
|
|
|
|
});
|
|
|
|
it("checks model dirtiness when altered, then reset diff", () => {
|
|
|
|
const article = getTestArticle();
|
|
|
|
expect(Article.model.model(article).isDirty()).toBeFalsy();
|
|
|
|
article.title = "new title";
|
|
|
|
expect(Article.model.model(article).isDirty()).toBeTruthy();
|
2025-06-23 20:31:34 +02:00
|
|
|
Article.model.model(article).resetDiff();
|
2025-03-29 22:59:13 +01:00
|
|
|
expect(Article.model.model(article).isDirty()).toBeFalsy();
|
|
|
|
});
|
|
|
|
|
|
|
|
it("deserializes a model from a serialized form", () => {
|
|
|
|
const expectedArticle = Object.assign(new Article(), {
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
Object.assign(new Account(), {
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: new Date("2022-08-07T08:47:01.000Z"),
|
|
|
|
active: true,
|
|
|
|
}),
|
|
|
|
Object.assign(new Account(), {
|
|
|
|
id: 4,
|
|
|
|
name: "Tester",
|
|
|
|
email: "another@test.test",
|
|
|
|
createdAt: new Date("2022-09-07T18:32:55.000Z"),
|
|
|
|
active: false,
|
|
|
|
}),
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
text: "this is a long test.",
|
|
|
|
evaluation: 8.52,
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-03-29 22:59:13 +01:00
|
|
|
comments: [
|
2025-06-23 20:31:34 +02:00
|
|
|
Object.assign(new ArticleComment(), {
|
|
|
|
id: 542,
|
|
|
|
author: Object.assign(new Account(), {
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: new Date("2022-08-07T08:47:01.000Z"),
|
|
|
|
active: true,
|
|
|
|
}),
|
|
|
|
message: "comment content",
|
|
|
|
}),
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
});
|
|
|
|
|
|
|
|
const deserializedArticle = Article.model.parse({
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 4,
|
|
|
|
name: "Tester",
|
|
|
|
email: "another@test.test",
|
|
|
|
createdAt: "2022-09-07T18:32:55.000Z",
|
|
|
|
active: false,
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
text: "this is a long test.",
|
|
|
|
evaluation: "8.52",
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-03-29 22:59:13 +01:00
|
|
|
comments: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 542,
|
|
|
|
author: {
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
message: "comment content",
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
});
|
|
|
|
|
2025-06-23 20:31:34 +02:00
|
|
|
const deserializedArticleProperties = Article.model
|
|
|
|
.model(deserializedArticle)
|
|
|
|
.getInstanceProperties();
|
2025-03-29 22:59:13 +01:00
|
|
|
delete deserializedArticleProperties.authors[0]._sharkitek;
|
|
|
|
delete deserializedArticleProperties.authors[1]._sharkitek;
|
|
|
|
delete deserializedArticleProperties.comments[0]._sharkitek;
|
|
|
|
delete (deserializedArticleProperties.comments[0].author as any)._sharkitek;
|
2025-06-23 20:31:34 +02:00
|
|
|
const expectedArticleProperties = Article.model
|
|
|
|
.model(expectedArticle)
|
|
|
|
.getInstanceProperties();
|
2025-03-29 22:59:13 +01:00
|
|
|
delete expectedArticleProperties.authors[0]._sharkitek;
|
|
|
|
delete expectedArticleProperties.authors[1]._sharkitek;
|
|
|
|
delete expectedArticleProperties.comments[0]._sharkitek;
|
|
|
|
delete (expectedArticleProperties.comments[0].author as any)._sharkitek;
|
|
|
|
expect(deserializedArticleProperties).toEqual(expectedArticleProperties);
|
|
|
|
});
|
|
|
|
|
|
|
|
it("serializes an initialized model", () => {
|
|
|
|
const article = getTestArticle();
|
|
|
|
expect(Article.model.model(article).serialize()).toEqual({
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
text: "this is a long test.",
|
|
|
|
evaluation: "25.23",
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-03-29 22:59:13 +01:00
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 52,
|
|
|
|
createdAt: article.authors[0].createdAt.toISOString(),
|
|
|
|
name: "John Doe",
|
|
|
|
email: "john@doe.test",
|
|
|
|
active: true,
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
comments: [],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("deserializes, changes and patches", () => {
|
|
|
|
const deserializedArticle = Article.model.parse({
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 4,
|
|
|
|
name: "Tester",
|
|
|
|
email: "another@test.test",
|
|
|
|
createdAt: "2022-09-07T18:32:55.000Z",
|
|
|
|
active: false,
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
text: "this is a long test.",
|
|
|
|
evaluation: "8.52",
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-03-29 22:59:13 +01:00
|
|
|
comments: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 542,
|
|
|
|
author: {
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
message: "comment content",
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
});
|
|
|
|
|
|
|
|
deserializedArticle.text = "A new text for a new life!";
|
|
|
|
|
|
|
|
expect(Article.model.model(deserializedArticle).patch()).toStrictEqual({
|
|
|
|
id: 1,
|
|
|
|
text: "A new text for a new life!",
|
|
|
|
});
|
|
|
|
|
|
|
|
deserializedArticle.evaluation = 5.24;
|
|
|
|
|
|
|
|
expect(Article.model.model(deserializedArticle).patch()).toStrictEqual({
|
|
|
|
id: 1,
|
|
|
|
evaluation: "5.24",
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("patches with modified submodels", () => {
|
|
|
|
const deserializedArticle = Article.model.parse({
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 4,
|
|
|
|
name: "Tester",
|
|
|
|
email: "another@test.test",
|
|
|
|
createdAt: "2022-09-07T18:32:55.000Z",
|
|
|
|
active: false,
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
text: "this is a long test.",
|
|
|
|
evaluation: "8.52",
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-03-29 22:59:13 +01:00
|
|
|
comments: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 542,
|
|
|
|
author: {
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
message: "comment content",
|
|
|
|
},
|
2025-03-29 22:59:13 +01:00
|
|
|
],
|
|
|
|
});
|
|
|
|
|
|
|
|
deserializedArticle.authors[1].active = true;
|
|
|
|
|
|
|
|
expect(Article.model.model(deserializedArticle).patch()).toStrictEqual({
|
|
|
|
id: 1,
|
2025-06-23 20:31:34 +02:00
|
|
|
authors: [{id: 52}, {id: 4, active: true}],
|
2025-03-29 22:59:13 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
deserializedArticle.comments[0].author.name = "Johnny";
|
|
|
|
|
|
|
|
expect(Article.model.model(deserializedArticle).patch()).toStrictEqual({
|
|
|
|
id: 1,
|
|
|
|
comments: [
|
|
|
|
{
|
|
|
|
id: 542,
|
|
|
|
author: {
|
|
|
|
id: 52,
|
|
|
|
name: "Johnny",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it("deserializes and patches with fields that are not properties", () => {
|
2025-06-23 20:31:34 +02:00
|
|
|
class TestModel {
|
2025-03-29 22:59:13 +01:00
|
|
|
static model = defineModel({
|
|
|
|
Class: TestModel,
|
|
|
|
properties: {
|
|
|
|
id: s.property.numeric(),
|
|
|
|
label: s.property.string(),
|
|
|
|
},
|
|
|
|
identifier: "id",
|
2025-06-23 20:31:34 +02:00
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
|
|
|
|
id: number;
|
|
|
|
label: string;
|
|
|
|
|
2025-06-23 20:31:34 +02:00
|
|
|
notAProperty: {hello: string} = {hello: "world"};
|
2025-03-29 22:59:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const deserializedModel = TestModel.model.parse({
|
|
|
|
id: 5,
|
|
|
|
label: "testing",
|
|
|
|
});
|
|
|
|
expect(deserializedModel.id).toBe(5);
|
|
|
|
expect(deserializedModel.label).toBe("testing");
|
|
|
|
expect(deserializedModel.notAProperty?.hello).toBe("world");
|
|
|
|
|
2025-06-23 20:31:34 +02:00
|
|
|
const clonedDeserializedModel = TestModel.model
|
|
|
|
.model(deserializedModel)
|
|
|
|
.clone();
|
2025-03-29 22:59:13 +01:00
|
|
|
|
|
|
|
deserializedModel.label = "new!";
|
2025-06-23 20:31:34 +02:00
|
|
|
expect(TestModel.model.model(deserializedModel).patch()).toStrictEqual({
|
|
|
|
id: 5,
|
|
|
|
label: "new!",
|
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
|
|
|
|
deserializedModel.notAProperty.hello = "monster";
|
2025-06-23 20:31:34 +02:00
|
|
|
expect(TestModel.model.model(deserializedModel).patch()).toStrictEqual({
|
|
|
|
id: 5,
|
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
|
2025-06-23 20:31:34 +02:00
|
|
|
expect(TestModel.model.model(deserializedModel).serialize()).toStrictEqual({
|
|
|
|
id: 5,
|
|
|
|
label: "new!",
|
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
|
2025-06-23 20:31:34 +02:00
|
|
|
expect(
|
|
|
|
TestModel.model.model(clonedDeserializedModel).serialize(),
|
|
|
|
).toStrictEqual({id: 5, label: "testing"});
|
2025-03-29 22:59:13 +01:00
|
|
|
expect(clonedDeserializedModel.notAProperty.hello).toEqual("world");
|
|
|
|
});
|
2025-04-20 20:30:27 +02:00
|
|
|
|
|
|
|
it("assigns properties, ignoring fields which are not properties", () => {
|
|
|
|
const deserializedArticle = Article.model.parse({
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 4,
|
|
|
|
name: "Tester",
|
|
|
|
email: "another@test.test",
|
|
|
|
createdAt: "2022-09-07T18:32:55.000Z",
|
|
|
|
active: false,
|
|
|
|
},
|
2025-04-20 20:30:27 +02:00
|
|
|
],
|
|
|
|
text: "this is a long test.",
|
|
|
|
evaluation: "8.52",
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-04-20 20:30:27 +02:00
|
|
|
comments: [
|
2025-06-23 20:31:34 +02:00
|
|
|
{
|
|
|
|
id: 542,
|
|
|
|
author: {
|
|
|
|
id: 52,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: "2022-08-07T08:47:01.000Z",
|
|
|
|
active: true,
|
|
|
|
},
|
|
|
|
message: "comment content",
|
|
|
|
},
|
2025-04-20 20:30:27 +02:00
|
|
|
],
|
|
|
|
});
|
|
|
|
|
|
|
|
// Assign title and text, html is silently ignored.
|
|
|
|
Article.model.model(deserializedArticle).assign({
|
|
|
|
title: "something else",
|
|
|
|
text: "fully new text! yes!",
|
|
|
|
html: "<p>fully new text! yes!</p>",
|
|
|
|
});
|
|
|
|
expect((deserializedArticle as any)?.html).toBeUndefined();
|
|
|
|
expect(Article.model.model(deserializedArticle).patch()).toStrictEqual({
|
|
|
|
id: 1,
|
|
|
|
title: "something else",
|
|
|
|
text: "fully new text! yes!",
|
|
|
|
});
|
|
|
|
});
|
2025-04-20 20:45:52 +02:00
|
|
|
|
|
|
|
it("initializes a model from properties values", () => {
|
|
|
|
const testArticle = Article.model.from({
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
Account.model.from({
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: new Date(),
|
|
|
|
active: true,
|
|
|
|
}),
|
2025-04-20 20:45:52 +02:00
|
|
|
],
|
|
|
|
text: "this is a long text",
|
|
|
|
evaluation: 8.52,
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-04-20 20:45:52 +02:00
|
|
|
|
|
|
|
unknownField: true,
|
|
|
|
anotherOne: "test",
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(testArticle.title).toBe("this is a test");
|
|
|
|
expect(testArticle.text).toBe("this is a long text");
|
|
|
|
expect(testArticle.evaluation).toBe(8.52);
|
|
|
|
expect(testArticle.authors).toHaveLength(1);
|
|
|
|
expect(testArticle.authors[0]?.name).toBe("John Doe");
|
|
|
|
expect((testArticle as any).unknownField).toBeUndefined();
|
|
|
|
expect((testArticle as any).anotherOne).toBeUndefined();
|
|
|
|
});
|
2025-06-22 17:25:12 +02:00
|
|
|
|
|
|
|
it("applies patches to an existing model", () => {
|
|
|
|
const testArticle = Article.model.from({
|
|
|
|
id: 1,
|
|
|
|
title: "this is a test",
|
|
|
|
authors: [
|
2025-06-23 20:31:34 +02:00
|
|
|
Account.model.from({
|
|
|
|
id: 55,
|
|
|
|
name: "John Doe",
|
|
|
|
email: "test@test.test",
|
|
|
|
createdAt: new Date(),
|
|
|
|
active: true,
|
|
|
|
}),
|
2025-06-22 17:25:12 +02:00
|
|
|
],
|
|
|
|
text: "this is a long text",
|
|
|
|
evaluation: 8.52,
|
2025-06-23 20:31:34 +02:00
|
|
|
tags: [{name: "test"}, {name: "foo"}],
|
2025-06-22 17:25:12 +02:00
|
|
|
|
|
|
|
unknownField: true,
|
|
|
|
anotherOne: "test",
|
|
|
|
});
|
|
|
|
Article.model.model(testArticle).resetDiff();
|
|
|
|
|
|
|
|
// Test simple patch.
|
|
|
|
Article.model.model(testArticle).applyPatch({
|
|
|
|
title: "new title",
|
|
|
|
});
|
|
|
|
expect(testArticle.title).toBe("new title");
|
2025-06-23 20:31:34 +02:00
|
|
|
expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({
|
|
|
|
id: 1,
|
|
|
|
});
|
2025-06-22 17:25:12 +02:00
|
|
|
|
|
|
|
// Test originals update propagation.
|
|
|
|
Article.model.model(testArticle).applyPatch({
|
2025-06-23 20:31:34 +02:00
|
|
|
authors: [{email: "john@test.test"}],
|
2025-06-22 17:25:12 +02:00
|
|
|
});
|
|
|
|
expect(testArticle.authors[0].email).toBe("john@test.test");
|
2025-06-23 20:31:34 +02:00
|
|
|
expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({
|
|
|
|
id: 1,
|
|
|
|
});
|
2025-06-22 17:25:12 +02:00
|
|
|
|
|
|
|
// Test without originals update.
|
2025-06-23 20:31:34 +02:00
|
|
|
Article.model.model(testArticle).applyPatch(
|
|
|
|
{
|
|
|
|
authors: [{name: "Johnny"}],
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
);
|
2025-06-22 17:25:12 +02:00
|
|
|
expect(testArticle.authors[0].name).toBe("Johnny");
|
|
|
|
expect(Article.model.model(testArticle).serializeDiff()).toStrictEqual({
|
|
|
|
id: 1,
|
2025-06-23 20:31:34 +02:00
|
|
|
authors: [{id: 55, name: "Johnny"}],
|
2025-06-22 17:25:12 +02:00
|
|
|
});
|
|
|
|
});
|
2025-03-29 22:59:13 +01:00
|
|
|
});
|