Skip to content

Commit

Permalink
Add contextual serialization test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Davide Caroselli committed Apr 20, 2024
1 parent de9eded commit 395dc71
Showing 1 changed file with 106 additions and 16 deletions.
122 changes: 106 additions & 16 deletions src/jsonthis.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import {CircularReferenceError, Jsonthis, ToJsonOptions} from "./Jsonthis";
import {JsonField, JsonSchema, JsonTraversalState} from "./schema";

function sequelize(jsonthis: Jsonthis, ...models: any) {
for (const model of models) {
// This is the same construct used to support Sequelize models.
jsonthis.registerGlobalSerializer(model, (value: any, state: JsonTraversalState, options?: ToJsonOptions) => {
const data = Object.assign({}, value);
const schema = JsonSchema.get(model);
return jsonthis.toJson(data, options, state, schema);
});

model.prototype.toJSON = function () {
return jsonthis.toJson(this);
}
}
}

describe("Jsonthis class", () => {
describe("registerGlobalSerializer method", () => {
function dateSerializer(value: Date): string {
Expand Down Expand Up @@ -292,27 +307,84 @@ describe("Jsonthis class", () => {
});
});

describe("with circular references", () => {
class Node {
public value: number;
public next?: Node;
describe("with context", () => {
function contextualMaskEmail(value: string, state: JsonTraversalState, opts?: ToJsonOptions): string {
const maskChar = opts?.context?.maskChar || "*";
return value.replace(/(?<=.).(?=[^@]*?.@)/g, maskChar);
}

const testCases = [
["simple Objects", false],
["Sequelize models", true],
];

constructor(value: number) {
this.value = value;
it.each(testCases)("on %s should serializer using context", (_, withSequelize) => {
class User {
id: number;
@JsonField({serializer: contextualMaskEmail})
email: string = "[email protected]"

constructor(id: number) {
this.id = id;
}
}
}

function sequelize(jsonthis: Jsonthis, ...models: any) {
for (const model of models) {
// This is the same construct used to support Sequelize models.
jsonthis.registerGlobalSerializer(model, (value: any, state: JsonTraversalState, options?: ToJsonOptions) => {
const data = Object.assign({}, value);
const schema = JsonSchema.get(model);
return jsonthis.toJson(data, options, state, schema);
});
const user = new User(1);

const jsonthis = new Jsonthis();
if (withSequelize) sequelize(jsonthis, User);

expect(jsonthis.toJson(user)).toStrictEqual({
id: 1,
email: "j******[email protected]"
});

expect(jsonthis.toJson(user, {context: {maskChar: "-"}})).toStrictEqual({
id: 1,
email: "[email protected]"
});
});

it.each(testCases)("on %s should pass context to nested objects", (_, withSequelize) => {
class User {
id: number;
@JsonField({serializer: contextualMaskEmail})
email: string
friend?: User;

constructor(id: number, email: string) {
this.id = id;
this.email = email;
}
}
}

const user = new User(1, "[email protected]");
user.friend = new User(2, "[email protected]");

const jsonthis = new Jsonthis();
if (withSequelize) sequelize(jsonthis, User);

expect(jsonthis.toJson(user)).toStrictEqual({
id: 1,
email: "j******[email protected]",
friend: {
id: 2,
email: "b*****[email protected]"
}
});

expect(jsonthis.toJson(user, {context: {maskChar: "-"}})).toStrictEqual({
id: 1,
email: "[email protected]",
friend: {
id: 2,
email: "[email protected]"
}
});
});
});

describe("with circular references", () => {
function circularReferenceSerializer(ref: any) {
return {"$ref": `$${ref.constructor.name}(${ref.value || ref.id})`}
}
Expand All @@ -325,6 +397,15 @@ describe("Jsonthis class", () => {
];

it.each(testCases)("on %s with direct circular reference", (_, withSequelize, withCRSerializer) => {
class Node {
public value: number;
public next?: Node;

constructor(value: number) {
this.value = value;
}
}

const node = new Node(1);
node.next = new Node(2);
node.next.next = node;
Expand All @@ -348,6 +429,15 @@ describe("Jsonthis class", () => {
});

it.each(testCases)("on %s with nested circular reference", (_, withSequelize, withCRSerializer) => {
class Node {
public value: number;
public next?: Node;

constructor(value: number) {
this.value = value;
}
}

const node = new Node(1);
node.next = new Node(2);
node.next.next = new Node(3);
Expand Down

0 comments on commit 395dc71

Please sign in to comment.