@saltcorn/markup 1.6.1-beta.0 → 1.7.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/builder.cjs +10 -0
- package/cjs/layout.cjs +10 -0
- package/cjs/mktag.cjs +10 -0
- package/cjs/table.cjs +10 -0
- package/cjs/tabs.cjs +10 -0
- package/cjs/workflow.cjs +10 -0
- package/dist/builder.d.ts +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +13 -3
- package/dist/builder.js.map +1 -1
- package/dist/emergency_layout.d.ts +30 -3
- package/dist/emergency_layout.d.ts.map +1 -1
- package/dist/emergency_layout.js +5 -6
- package/dist/emergency_layout.js.map +1 -1
- package/dist/extra_tags.d.ts +31 -0
- package/dist/extra_tags.d.ts.map +1 -0
- package/dist/extra_tags.js +54 -0
- package/dist/extra_tags.js.map +1 -0
- package/dist/form.d.ts +21 -1
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +13 -14
- package/dist/form.js.map +1 -1
- package/dist/form.test.js +48 -84
- package/dist/form.test.js.map +1 -1
- package/dist/generated_tags.d.ts +127 -0
- package/dist/generated_tags.d.ts.map +1 -0
- package/dist/generated_tags.js +253 -0
- package/dist/generated_tags.js.map +1 -0
- package/dist/helpers.d.ts +95 -53
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +3 -3
- package/dist/helpers.js.map +1 -1
- package/dist/helpers.test.js +123 -127
- package/dist/helpers.test.js.map +1 -1
- package/dist/index.d.ts +95 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +29 -2
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +24 -10
- package/dist/internal.js.map +1 -1
- package/dist/layout.d.ts +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +124 -97
- package/dist/layout.js.map +1 -1
- package/dist/layout.test.js +130 -167
- package/dist/layout.test.js.map +1 -1
- package/dist/layout_utils.d.ts +142 -2
- package/dist/layout_utils.d.ts.map +1 -1
- package/dist/layout_utils.js +7 -4
- package/dist/layout_utils.js.map +1 -1
- package/dist/layout_utils.test.js +49 -53
- package/dist/layout_utils.test.js.map +1 -1
- package/dist/markup.test.js +227 -264
- package/dist/markup.test.js.map +1 -1
- package/dist/mjml-layout.d.ts +31 -1
- package/dist/mjml-layout.d.ts.map +1 -1
- package/dist/mjml-layout.js +4 -4
- package/dist/mjml-layout.js.map +1 -1
- package/dist/mjml-tags.d.ts +40 -4
- package/dist/mjml-tags.d.ts.map +1 -1
- package/dist/mjml-tags.js +31 -21
- package/dist/mjml-tags.js.map +1 -1
- package/dist/mktag.d.ts +2 -2
- package/dist/mktag.d.ts.map +1 -1
- package/dist/mktag.js +1 -2
- package/dist/mktag.js.map +1 -1
- package/dist/table.d.ts +3 -1
- package/dist/table.d.ts.map +1 -1
- package/dist/table.js +63 -16
- package/dist/table.js.map +1 -1
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.d.ts.map +1 -1
- package/dist/tabs.js +2 -3
- package/dist/tabs.js.map +1 -1
- package/dist/tags.d.ts +7 -2
- package/dist/tags.d.ts.map +1 -1
- package/dist/tags.js +16 -94
- package/dist/tags.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +2 -3
- package/dist/workflow.js.map +1 -1
- package/package.json +46 -12
- /package/{webpack.config.js → webpack.config.cjs} +0 -0
package/dist/markup.test.js
CHANGED
|
@@ -1,123 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
const globals_1 = require("@jest/globals");
|
|
40
|
-
const mjml_layout_1 = require("./mjml-layout");
|
|
41
|
-
const tags = __importStar(require("./tags"));
|
|
42
|
-
const mjml = __importStar(require("./mjml-tags"));
|
|
43
|
-
const tabs_1 = __importDefault(require("./tabs"));
|
|
44
|
-
const table_1 = __importDefault(require("./table"));
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import { expect } from "@saltcorn/db-common/test_expect";
|
|
3
|
+
import { transformTextStyle, transformLinkSize, applyTextStyle, renderMJML, } from "./mjml-layout.js";
|
|
4
|
+
import * as tags from "./tags.js";
|
|
5
|
+
import * as mjml from "./mjml-tags.js";
|
|
6
|
+
import tabs from "./tabs.js";
|
|
7
|
+
import mkTable from "./table.js";
|
|
45
8
|
// import index = require("./index");
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const { post_btn, post_delete_btn, post_dropdown_item, settingsDropdown, localeDate, } =
|
|
9
|
+
import index from "./index.js";
|
|
10
|
+
import builder from "./builder.js";
|
|
11
|
+
const { post_btn, post_delete_btn, post_dropdown_item, settingsDropdown, localeDate, } = index;
|
|
49
12
|
const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
13
|
+
describe("tags", () => {
|
|
14
|
+
it("renders", () => {
|
|
15
|
+
expect(a({ href: "/" }, "Home")).toBe('<a href="/">Home</a>');
|
|
16
|
+
expect(a({ href: "/" }, ["Home", " Sweet", " Home"])).toBe('<a href="/">Home Sweet Home</a>');
|
|
17
|
+
expect(a({ href: "/", class: "centre" }, "Home")).toBe('<a href="/" class="centre">Home</a>');
|
|
18
|
+
expect(input({ type: "text" })).toBe('<input type="text">');
|
|
19
|
+
expect(div(5)).toBe("<div>5</div>");
|
|
20
|
+
expect(div()).toBe("<div></div>");
|
|
21
|
+
expect(div(null)).toBe("<div></div>");
|
|
22
|
+
expect(div("Hello world")).toBe("<div>Hello world</div>");
|
|
23
|
+
expect(div(["Hello world"])).toBe("<div>Hello world</div>");
|
|
24
|
+
expect(i()).toBe("<i></i>");
|
|
25
|
+
expect(hr()).toBe("<hr>");
|
|
26
|
+
expect(div(["hello ", "world"])).toBe("<div>hello world</div>");
|
|
27
|
+
expect(ul({ class: "foo" }, [false, "hello ", "world"])).toBe(`<ul class="foo">hello world</ul>`);
|
|
28
|
+
expect(ul({ class: "foo" }, [["hello ", "world"]])).toBe(`<ul class="foo">hello world</ul>`);
|
|
29
|
+
expect(i({ class: "fas fa-plus-square" })).toBe('<i class="fas fa-plus-square"></i>');
|
|
30
|
+
expect(genericElement("div", { class: "foo" }, "Hello")).toBe('<div class="foo">Hello</div>');
|
|
31
|
+
expect(genericElement("div", { onclick: `$("#bar").hide()` }, "Hello")).toBe('<div onclick="$("#bar").hide()">Hello</div>');
|
|
32
|
+
});
|
|
33
|
+
it("class", () => {
|
|
34
|
+
expect(div({ class: "foo" }, 5)).toBe('<div class="foo">5</div>');
|
|
35
|
+
expect(div({ class: false }, 5)).toBe("<div>5</div>");
|
|
36
|
+
expect(div({ class: "foo bar" }, 5)).toBe('<div class="foo bar">5</div>');
|
|
37
|
+
expect(div({ class: ["foo", "bar"] }, 5)).toBe('<div class="foo bar">5</div>');
|
|
38
|
+
expect(div({ class: ["foo", " "] }, 5)).toBe('<div class="foo ">5</div>');
|
|
39
|
+
expect(input({ class: ["foo", " "] })).toBe('<input class="foo ">');
|
|
40
|
+
expect(div({ class: ["foo bar", "", undefined, null, false, "baz"] }, 5)).toBe('<div class="foo bar baz">5</div>');
|
|
41
|
+
expect(div({ class: [undefined, null, false] }, 5)).toBe("<div>5</div>");
|
|
42
|
+
expect(hr({ class: "foo" })).toBe('<hr class="foo">');
|
|
43
|
+
});
|
|
44
|
+
it("style", () => {
|
|
45
|
+
expect(div({ style: "color:red;border:1px solid black" }, 5)).toBe('<div style="color:red;border:1px solid black">5</div>');
|
|
46
|
+
expect(div({ style: ["color:red", "border:1px solid black"] }, 5)).toBe('<div style="color:red;border:1px solid black">5</div>');
|
|
47
|
+
expect(div({ style: ["color:red", false, undefined, "border:1px solid black"] }, 5)).toBe('<div style="color:red;border:1px solid black">5</div>');
|
|
48
|
+
expect(div({ style: { color: "red", border: "1px solid black" } }, 5)).toBe('<div style="color:red;border:1px solid black">5</div>');
|
|
49
|
+
expect(div({ style: { marginRight: "1px", border: "1px solid black" } }, 5)).toBe('<div style="margin-right:1px;border:1px solid black">5</div>');
|
|
87
50
|
//border-top-left-radius
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
51
|
+
expect(div({ style: { marginRight: "1px", borderTopLeftRadius: "3px" } }, 5)).toBe('<div style="margin-right:1px;border-top-left-radius:3px">5</div>');
|
|
52
|
+
expect(hr({ style: { color: "red", display: null } }, 5)).toBe('<hr style="color:red">');
|
|
53
|
+
expect(hr({ style: { color: "red", display: "" } }, 5)).toBe('<hr style="color:red">');
|
|
54
|
+
expect(hr({ style: { color: "red", display: "none" } }, 5)).toBe('<hr style="color:red;display:none">');
|
|
55
|
+
expect(hr({ style: { color: "", display: null } }, 5)).toBe("<hr>");
|
|
56
|
+
expect(hr({ style: { color: "red" } }, 5)).toBe('<hr style="color:red">');
|
|
57
|
+
expect(hr({ style: {} })).toBe("<hr>");
|
|
58
|
+
expect(hr({ style: null })).toBe("<hr>");
|
|
59
|
+
expect(div({ class: "foo", style: null })).toBe('<div class="foo"></div>');
|
|
60
|
+
});
|
|
61
|
+
it("escaping", () => {
|
|
62
|
+
expect(text("foo")).toBe("foo");
|
|
63
|
+
expect(text_attr('" onMouseOver="alert(1);')).toBe("" onMouseOver="alert(1);");
|
|
64
|
+
expect(text(1)).toBe("1");
|
|
65
|
+
expect(text(0)).toBe("0");
|
|
66
|
+
expect(text("<script>alert(1);<script>")).toBe("<script>alert(1);<script>");
|
|
67
|
+
expect(text("<p>alert<p>")).toBe("<p>alert<p>");
|
|
68
|
+
expect(text("<kbd>ctrl<kbd>")).toBe("<kbd>ctrl<kbd>");
|
|
69
|
+
expect(text('<span style="color:#2ecc71;">green</span>')).toBe('<span style="color:#2ecc71;">green</span>');
|
|
70
|
+
expect(text('<article style="color:#2ecc71;">green</article>')).toBe("<article>green</article>");
|
|
71
|
+
expect(text('<article style="color:#2ecc71;">green</article>', {
|
|
109
72
|
article: ["style"],
|
|
110
73
|
})).toBe('<article style="color:#2ecc71;">green</article>');
|
|
111
|
-
|
|
74
|
+
expect(text('<progress onclick="foo()">green</progress>', {
|
|
112
75
|
progress: ["onclick"],
|
|
113
76
|
})).toBe('<progress onclick="foo()">green</progress>');
|
|
114
77
|
});
|
|
115
78
|
});
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
79
|
+
describe("mjml tags", () => {
|
|
80
|
+
it("renders", () => {
|
|
81
|
+
expect(mjml.mjml(mjml.body(mjml.section({ "background-color": "#f0f0f0" }, mjml.text("hello world"))))).toBe('<mjml><mj-body><mj-section background-color="#f0f0f0"><mj-text>hello world</mj-text></mj-section></mj-body></mjml>');
|
|
119
82
|
});
|
|
120
|
-
|
|
83
|
+
it("renders emailButton with default style", () => {
|
|
121
84
|
const result = mjml.emailButton({
|
|
122
85
|
href: "https://example.com",
|
|
123
86
|
title: "Click Me",
|
|
@@ -135,9 +98,9 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
135
98
|
`
|
|
136
99
|
.replace(/\s+/g, " ")
|
|
137
100
|
.trim();
|
|
138
|
-
|
|
101
|
+
expect(result.replace(/\s+/g, " ").trim()).toBe(expected);
|
|
139
102
|
});
|
|
140
|
-
|
|
103
|
+
it("renders emailButton with btn-primary style", () => {
|
|
141
104
|
const result = mjml.emailButton({
|
|
142
105
|
href: "https://example.com",
|
|
143
106
|
title: "Click Me",
|
|
@@ -146,16 +109,16 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
146
109
|
const expected = '<a rel="noopener" target="_blank" title="Click Me" href="https://example.com" style="background-color: #0d6efd; color: #ffffff; font-size: 18px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; text-decoration: none; padding: 14px 20px; border-radius: 5px; display: inline-block; mso-padding-alt: 0;"> <!--[if mso]> <i style="letter-spacing: 25px; mso-font-width: -100%; mso-text-raise: 30pt;"> </i> <![endif]--> <span style="mso-text-raise: 15pt;">Click Me</span> <!--[if mso]> <i style="letter-spacing: 25px; mso-font-width: -100%;"> </i> <![endif]--> </a>'
|
|
147
110
|
.replace(/\s+/g, " ")
|
|
148
111
|
.trim();
|
|
149
|
-
|
|
112
|
+
expect(result.replace(/\s+/g, " ").trim()).toBe(expected);
|
|
150
113
|
});
|
|
151
|
-
|
|
114
|
+
it("renders emailButton with btn-outline-primary style", () => {
|
|
152
115
|
const result = mjml.emailButton({ href: "https://example.com", btnStyle: "btn-outline-primary" }, "Click Me");
|
|
153
116
|
const expected = '<a rel="noopener" target="_blank" href="https://example.com" style="background-color: transparent; color: #0d6efd; border-color: #0d6efd;border-width:1px; border-style: solid; font-size: 18px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; text-decoration: none; padding: 14px 20px; border-radius: 5px; display: inline-block; mso-padding-alt: 0;"> <!--[if mso]> <i style="letter-spacing: 25px; mso-font-width: -100%; mso-text-raise: 30pt;"> </i> <![endif]--> <span style="mso-text-raise: 15pt;">Click Me</span> <!--[if mso]> <i style="letter-spacing: 25px; mso-font-width: -100%;"> </i> <![endif]--> </a>'
|
|
154
117
|
.replace(/\s+/g, " ")
|
|
155
118
|
.trim();
|
|
156
|
-
|
|
119
|
+
expect(result.replace(/\s+/g, " ").trim()).toBe(expected);
|
|
157
120
|
});
|
|
158
|
-
|
|
121
|
+
it("renders emailButton with custom title and style", () => {
|
|
159
122
|
const result = mjml.emailButton({
|
|
160
123
|
href: "https://example.com",
|
|
161
124
|
title: "Custom Title",
|
|
@@ -165,34 +128,34 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
165
128
|
const expected = '<a rel="noopener" target="_blank" title="Custom Title" href="https://example.com" style="color: #fff; background-color: #000; border-width: 1px; border-style: solid; font-size: 18px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; text-decoration: none; padding: 14px 20px; border-radius: 5px; display: inline-block; mso-padding-alt: 0;"> <!--[if mso]> <i style="letter-spacing: 25px; mso-font-width: -100%; mso-text-raise: 30pt;"> </i> <![endif]--> <span style="mso-text-raise: 15pt;">Click Me</span> <!--[if mso]> <i style="letter-spacing: 25px; mso-font-width: -100%;"> </i> <![endif]--> </a>'
|
|
166
129
|
.replace(/\s+/g, " ")
|
|
167
130
|
.trim();
|
|
168
|
-
|
|
131
|
+
expect(result.replace(/\s+/g, " ").trim()).toBe(expected);
|
|
169
132
|
});
|
|
170
133
|
});
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const result = (
|
|
134
|
+
describe("tabs", () => {
|
|
135
|
+
it("renders tabs with single content", () => {
|
|
136
|
+
const result = tabs({
|
|
174
137
|
Tab1: "Content1",
|
|
175
138
|
});
|
|
176
|
-
|
|
139
|
+
expect(result).toBe(`<ul class="nav nav-tabs" role="tablist"><li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#Tab1" id="Tab1-tab" role="tab" aria-controls="home" aria-selected="true">Tab1</a></li></ul><div class="tab-content"><div class="tab-pane fade show active" id="Tab1" role="tabpanel" aria-labelledby="Tab1-tab">Content1</div></div>`);
|
|
177
140
|
});
|
|
178
|
-
|
|
179
|
-
const result = (
|
|
180
|
-
|
|
141
|
+
it("renders tabs with multiple contents", () => {
|
|
142
|
+
const result = tabs({ Tab1: "Content1", Tab2: "Content2" });
|
|
143
|
+
expect(result).toBe(`<ul class="nav nav-tabs" role="tablist"><li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#Tab1" id="Tab1-tab" role="tab" aria-controls="home" aria-selected="true">Tab1</a></li><li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#Tab2" id="Tab2-tab" role="tab" aria-controls="home" aria-selected="true">Tab2</a></li></ul><div class="tab-content"><div class="tab-pane fade show active" id="Tab1" role="tabpanel" aria-labelledby="Tab1-tab">Content1</div><div class="tab-pane fade" id="Tab2" role="tabpanel" aria-labelledby="Tab2-tab">Content2</div></div>`);
|
|
181
144
|
});
|
|
182
|
-
|
|
183
|
-
const result = (
|
|
145
|
+
it("renders tabs from an array of entries", () => {
|
|
146
|
+
const result = tabs([
|
|
184
147
|
["Tab1", "Content1"],
|
|
185
148
|
["Tab2", "Content2"],
|
|
186
149
|
]);
|
|
187
|
-
|
|
150
|
+
expect(result).toBe(`<ul class="nav nav-tabs" role="tablist"><li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#Tab1" id="Tab1-tab" role="tab" aria-controls="home" aria-selected="true">Tab1</a></li><li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#Tab2" id="Tab2-tab" role="tab" aria-controls="home" aria-selected="true">Tab2</a></li></ul><div class="tab-content"><div class="tab-pane fade show active" id="Tab1" role="tabpanel" aria-labelledby="Tab1-tab">Content1</div><div class="tab-pane fade" id="Tab2" role="tabpanel" aria-labelledby="Tab2-tab">Content2</div></div>`);
|
|
188
151
|
});
|
|
189
|
-
|
|
190
|
-
const result = (
|
|
191
|
-
|
|
152
|
+
it("handles empty tabs gracefully", () => {
|
|
153
|
+
const result = tabs({});
|
|
154
|
+
expect(result).toBe(`<ul class="nav nav-tabs" role="tablist"></ul><div class="tab-content"></div>`);
|
|
192
155
|
});
|
|
193
156
|
});
|
|
194
|
-
|
|
195
|
-
|
|
157
|
+
describe("table", () => {
|
|
158
|
+
it("renders a basic table", () => {
|
|
196
159
|
const headers = [
|
|
197
160
|
{ label: "Name", key: "name" },
|
|
198
161
|
{ label: "Age", key: "age" },
|
|
@@ -201,10 +164,10 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
201
164
|
{ name: "UserName1", age: 25, id: 1 },
|
|
202
165
|
{ name: "UserName2", age: 30, id: 2 },
|
|
203
166
|
];
|
|
204
|
-
const result = (
|
|
205
|
-
|
|
167
|
+
const result = mkTable(headers, rows);
|
|
168
|
+
expect(result).toBe(`<div class="table-responsive"><table class="table table-sm"><thead><tr><th>Name</th><th>Age</th></tr></thead><tbody><tr data-row-id="1"><td>UserName1</td><td>25</td></tr><tr data-row-id="2"><td>UserName2</td><td>30</td></tr></tbody></table></div>`);
|
|
206
169
|
});
|
|
207
|
-
|
|
170
|
+
it("renders a tramnsposed table", () => {
|
|
208
171
|
const headers = [
|
|
209
172
|
{
|
|
210
173
|
label: "Name",
|
|
@@ -219,10 +182,10 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
219
182
|
{ name: "UserName1", age: 25 },
|
|
220
183
|
{ name: "UserName2", age: 30 },
|
|
221
184
|
];
|
|
222
|
-
const result = (
|
|
223
|
-
|
|
185
|
+
const result = mkTable(headers, rows, { transpose: true });
|
|
186
|
+
expect(result).toBe(`<div class="table-responsive"><table class="table table-sm"><tbody><tr row-key="name"><th>Name</th><td>UserName1</td><td>UserName2</td></tr><tr row-key="age"><th>Age</th><td>25</td><td>30</td></tr></tbody></table></div>`);
|
|
224
187
|
});
|
|
225
|
-
|
|
188
|
+
it("renders a transposed table", () => {
|
|
226
189
|
const headers = [
|
|
227
190
|
{
|
|
228
191
|
label: "Name",
|
|
@@ -237,10 +200,10 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
237
200
|
{ name: "UserName1", age: 25 },
|
|
238
201
|
{ name: "UserName2", age: 30 },
|
|
239
202
|
];
|
|
240
|
-
const result = (
|
|
241
|
-
|
|
203
|
+
const result = mkTable(headers, rows, { transpose: true });
|
|
204
|
+
expect(result).toBe(`<div class="table-responsive"><table class="table table-sm"><tbody><tr row-key="name"><th>Name</th><td>UserName1</td><td>UserName2</td></tr><tr row-key="age"><th>Age</th><td>25</td><td>30</td></tr></tbody></table></div>`);
|
|
242
205
|
});
|
|
243
|
-
|
|
206
|
+
it("renders a table with pagination", () => {
|
|
244
207
|
const headers = [
|
|
245
208
|
{ label: "Name", key: "name" },
|
|
246
209
|
{ label: "Age", key: "age" },
|
|
@@ -254,14 +217,14 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
254
217
|
pages: 3,
|
|
255
218
|
get_page_link: (page) => `?page=${page}`,
|
|
256
219
|
};
|
|
257
|
-
const result = (
|
|
258
|
-
|
|
220
|
+
const result = mkTable(headers, rows, { pagination: paginationOpts });
|
|
221
|
+
expect(result).toBe(`<div class="table-responsive"><table class="table table-sm"><thead><tr><th>Name</th><th>Age</th></tr></thead><tbody><tr data-row-id="1"><td>UserName1</td><td>25</td></tr><tr data-row-id="2"><td>UserName2</td><td>30</td></tr></tbody></table><ul class="pagination"><li class="page-item active"><span class="page-link link-style" onclick="?page=1" role="link">1</span></li><li class="page-item"><span class="page-link link-style" onclick="?page=2" role="link">2</span></li><li class="page-item"><span class="page-link link-style" onclick="?page=3" role="link">3</span></li></ul></div>`);
|
|
259
222
|
});
|
|
260
223
|
});
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
224
|
+
describe("mjml-layout", () => {
|
|
225
|
+
describe("transformTextStyle", () => {
|
|
226
|
+
it("transforms text styles correctly", () => {
|
|
227
|
+
expect(transformTextStyle("h1")).toEqual({
|
|
265
228
|
"font-size": "2em",
|
|
266
229
|
"margin-top": "0.67em",
|
|
267
230
|
"margin-bottom": "0.67em",
|
|
@@ -269,35 +232,35 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
269
232
|
"margin-right": 0,
|
|
270
233
|
"font-weight": "bold",
|
|
271
234
|
});
|
|
272
|
-
|
|
235
|
+
expect(transformTextStyle("fw-bold")).toEqual({
|
|
273
236
|
"font-weight": "700 !important",
|
|
274
237
|
});
|
|
275
|
-
|
|
238
|
+
expect(transformTextStyle("text-muted")).toEqual({
|
|
276
239
|
"--bs-text-opacity": "1",
|
|
277
240
|
color: "#858796 !important",
|
|
278
241
|
});
|
|
279
242
|
});
|
|
280
|
-
|
|
281
|
-
|
|
243
|
+
it("returns an empty object for unknown styles", () => {
|
|
244
|
+
expect(transformTextStyle("unknown-style")).toEqual({});
|
|
282
245
|
});
|
|
283
246
|
});
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
247
|
+
describe("transformLinkSize", () => {
|
|
248
|
+
it("transforms link sizes correctly", () => {
|
|
249
|
+
expect(transformLinkSize("btn-lg")).toEqual({
|
|
287
250
|
padding: "0.5rem 1rem",
|
|
288
251
|
"font-size": "1.25rem",
|
|
289
252
|
});
|
|
290
|
-
|
|
253
|
+
expect(transformLinkSize("btn-sm")).toEqual({
|
|
291
254
|
padding: "0.25rem 0.5rem",
|
|
292
255
|
"font-size": "0.875rem",
|
|
293
256
|
});
|
|
294
257
|
});
|
|
295
|
-
|
|
296
|
-
|
|
258
|
+
it("returns an empty object for unknown sizes", () => {
|
|
259
|
+
expect(transformLinkSize("unkown-size")).toEqual({});
|
|
297
260
|
});
|
|
298
261
|
});
|
|
299
|
-
|
|
300
|
-
|
|
262
|
+
describe("applyTextStyle", () => {
|
|
263
|
+
it("applies text style to block elements", () => {
|
|
301
264
|
const segment = {
|
|
302
265
|
textStyle: "h1",
|
|
303
266
|
inline: false,
|
|
@@ -306,33 +269,33 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
306
269
|
},
|
|
307
270
|
};
|
|
308
271
|
const inner = "Hello World";
|
|
309
|
-
const result =
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
272
|
+
const result = applyTextStyle(segment, inner);
|
|
273
|
+
expect(result).toContain('<div style="');
|
|
274
|
+
expect(result).toContain("font-size:2em");
|
|
275
|
+
expect(result).toContain("color:red");
|
|
313
276
|
});
|
|
314
|
-
|
|
277
|
+
it("applies text styles to inline elements", () => {
|
|
315
278
|
const segment = {
|
|
316
279
|
textStyle: "fw-bold",
|
|
317
280
|
inline: true,
|
|
318
281
|
style: { color: "blue" },
|
|
319
282
|
};
|
|
320
283
|
const inner = "Hello World";
|
|
321
|
-
const result =
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
284
|
+
const result = applyTextStyle(segment, inner);
|
|
285
|
+
expect(result).toContain('<span style="');
|
|
286
|
+
expect(result).toContain("font-weight:700 !important");
|
|
287
|
+
expect(result).toContain("color:blue");
|
|
288
|
+
expect(result).toContain("Hello World");
|
|
326
289
|
});
|
|
327
|
-
|
|
290
|
+
it("returns inner content without wrapping if no styles are applied", () => {
|
|
328
291
|
const segment = { textStyle: null, style: {} };
|
|
329
292
|
const inner = "Hello World";
|
|
330
|
-
const result =
|
|
331
|
-
|
|
293
|
+
const result = applyTextStyle(segment, inner);
|
|
294
|
+
expect(result).toBe("Hello World");
|
|
332
295
|
});
|
|
333
296
|
});
|
|
334
|
-
|
|
335
|
-
|
|
297
|
+
describe("renderMJML", () => {
|
|
298
|
+
it("renders a layout with an image", () => {
|
|
336
299
|
const layout = {
|
|
337
300
|
type: "container",
|
|
338
301
|
contents: [
|
|
@@ -351,13 +314,13 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
351
314
|
isSubView: false,
|
|
352
315
|
get_base_url: () => "https://example.com",
|
|
353
316
|
};
|
|
354
|
-
const result =
|
|
317
|
+
const result = renderMJML({
|
|
355
318
|
layout,
|
|
356
319
|
req,
|
|
357
320
|
});
|
|
358
|
-
|
|
321
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;"><img style="width:100%" alt="Test Image" src="https://example.com/files/serve/1"></div></mj-raw></mj-section>`);
|
|
359
322
|
});
|
|
360
|
-
|
|
323
|
+
it("renders a layout with a link", () => {
|
|
361
324
|
const layout = {
|
|
362
325
|
type: "container",
|
|
363
326
|
contents: [
|
|
@@ -369,7 +332,7 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
369
332
|
},
|
|
370
333
|
],
|
|
371
334
|
};
|
|
372
|
-
const result =
|
|
335
|
+
const result = renderMJML({ layout, req: { isSubView: false } });
|
|
373
336
|
const expected = `<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;"><a rel="noopener" target="_blank" href="https://example.com" style="background-color: #0d6efd; color: #ffffff; font-size: 18px; font-family: Helvetica, Arial, sans-serif; font-weight: bold; text-decoration: none; padding: 14px 20px; border-radius: 5px; display: inline-block; mso-padding-alt: 0;">
|
|
374
337
|
<!--[if mso]>
|
|
375
338
|
<i style="letter-spacing: 25px; mso-font-width: -100%; mso-text-raise: 30pt;"> </i>
|
|
@@ -381,9 +344,9 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
381
344
|
</a></div></mj-raw></mj-section>`
|
|
382
345
|
.replace(/\s+/g, " ")
|
|
383
346
|
.trim();
|
|
384
|
-
|
|
347
|
+
expect(result.markup.replace(/\s+/g, " ").trim()).toBe(expected);
|
|
385
348
|
});
|
|
386
|
-
|
|
349
|
+
it("renders a layout with nested containers", () => {
|
|
387
350
|
const layout = {
|
|
388
351
|
type: "container",
|
|
389
352
|
contents: [
|
|
@@ -399,7 +362,7 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
399
362
|
},
|
|
400
363
|
],
|
|
401
364
|
};
|
|
402
|
-
const result =
|
|
365
|
+
const result = renderMJML({
|
|
403
366
|
layout,
|
|
404
367
|
req: { isSubView: false },
|
|
405
368
|
});
|
|
@@ -407,9 +370,9 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
407
370
|
.replace(/\s+/g, " ")
|
|
408
371
|
.trim();
|
|
409
372
|
const recieved = result.markup.replace(/\s+/g, " ").trim();
|
|
410
|
-
|
|
373
|
+
expect(recieved).toBe(expected);
|
|
411
374
|
});
|
|
412
|
-
|
|
375
|
+
it("renders a layout with a card", () => {
|
|
413
376
|
const layout = {
|
|
414
377
|
type: "container",
|
|
415
378
|
contents: [
|
|
@@ -420,7 +383,7 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
420
383
|
},
|
|
421
384
|
],
|
|
422
385
|
};
|
|
423
|
-
const result =
|
|
386
|
+
const result = renderMJML({
|
|
424
387
|
layout,
|
|
425
388
|
req: { isSubView: false },
|
|
426
389
|
});
|
|
@@ -428,9 +391,9 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
428
391
|
.replace(/\s+/g, " ")
|
|
429
392
|
.trim();
|
|
430
393
|
const recieved = result.markup.replace(/\s+/g, " ").trim();
|
|
431
|
-
|
|
394
|
+
expect(recieved).toBe(expected);
|
|
432
395
|
});
|
|
433
|
-
|
|
396
|
+
it("renders a layout with tabs", () => {
|
|
434
397
|
const layout = {
|
|
435
398
|
type: "tabs",
|
|
436
399
|
contents: [
|
|
@@ -443,7 +406,7 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
443
406
|
},
|
|
444
407
|
],
|
|
445
408
|
};
|
|
446
|
-
const result =
|
|
409
|
+
const result = renderMJML({
|
|
447
410
|
layout,
|
|
448
411
|
req: { isSubView: false },
|
|
449
412
|
});
|
|
@@ -451,10 +414,10 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
451
414
|
.replace(/\s+/g, " ")
|
|
452
415
|
.trim();
|
|
453
416
|
const recieved = result.markup.replace(/\s+/g, " ").trim();
|
|
454
|
-
|
|
417
|
+
expect(recieved).toBe(expected);
|
|
455
418
|
});
|
|
456
419
|
});
|
|
457
|
-
|
|
420
|
+
it("renders a layout with a page header", () => {
|
|
458
421
|
const layout = {
|
|
459
422
|
type: "container",
|
|
460
423
|
contents: [
|
|
@@ -465,10 +428,10 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
465
428
|
},
|
|
466
429
|
],
|
|
467
430
|
};
|
|
468
|
-
const result =
|
|
469
|
-
|
|
431
|
+
const result = renderMJML({ layout, req: { isSubView: false } });
|
|
432
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;"><h1>Welcome</h1><p>This is a test page header</p></div></mj-raw></mj-section>`);
|
|
470
433
|
});
|
|
471
|
-
|
|
434
|
+
it("renders layout with a table", () => {
|
|
472
435
|
const layout = {
|
|
473
436
|
type: "container",
|
|
474
437
|
contents: [
|
|
@@ -489,13 +452,13 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
489
452
|
},
|
|
490
453
|
],
|
|
491
454
|
};
|
|
492
|
-
const result =
|
|
455
|
+
const result = renderMJML({
|
|
493
456
|
layout,
|
|
494
457
|
req: { isSubView: false },
|
|
495
458
|
});
|
|
496
|
-
|
|
459
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;"><table><tbody><tr><td>Cell 1</td><td>Cell 2</td></tr><tr><td>Cell 3</td><td>Cell 4</td></tr></tbody></table></div></mj-raw></mj-section>`);
|
|
497
460
|
});
|
|
498
|
-
|
|
461
|
+
it("renders a layout with a dropdown menu", () => {
|
|
499
462
|
const layout = {
|
|
500
463
|
type: "container",
|
|
501
464
|
contents: [
|
|
@@ -514,10 +477,10 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
514
477
|
},
|
|
515
478
|
],
|
|
516
479
|
};
|
|
517
|
-
const result =
|
|
518
|
-
|
|
480
|
+
const result = renderMJML({ layout, req: { isSubView: false } });
|
|
481
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;"></div></mj-raw></mj-section>`);
|
|
519
482
|
});
|
|
520
|
-
|
|
483
|
+
it("renders a layout with conditional visibility based on role", () => {
|
|
521
484
|
const layout = {
|
|
522
485
|
type: "container",
|
|
523
486
|
contents: [
|
|
@@ -532,20 +495,20 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
532
495
|
},
|
|
533
496
|
],
|
|
534
497
|
};
|
|
535
|
-
const resultForAdmin =
|
|
498
|
+
const resultForAdmin = renderMJML({
|
|
536
499
|
layout,
|
|
537
500
|
req: { isSubView: false },
|
|
538
501
|
role: 1,
|
|
539
502
|
});
|
|
540
|
-
const resultForUser =
|
|
503
|
+
const resultForUser = renderMJML({
|
|
541
504
|
layout,
|
|
542
505
|
req: { isSubView: false },
|
|
543
506
|
role: 2,
|
|
544
507
|
});
|
|
545
|
-
|
|
546
|
-
|
|
508
|
+
expect(resultForAdmin.markup).toContain(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;">Visible to allVisible to admins only</div></mj-raw></mj-section>`);
|
|
509
|
+
expect(resultForUser.markup).toContain(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;">Visible to all</div></mj-raw></mj-section>`);
|
|
547
510
|
});
|
|
548
|
-
|
|
511
|
+
it("renders a layout with a gradient background", () => {
|
|
549
512
|
const layout = {
|
|
550
513
|
type: "container",
|
|
551
514
|
bgType: "Gradient",
|
|
@@ -554,52 +517,52 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
554
517
|
gradDirection: 45,
|
|
555
518
|
contents: [{ type: "blank", contents: "Gradient Background" }],
|
|
556
519
|
};
|
|
557
|
-
const result =
|
|
558
|
-
|
|
520
|
+
const result = renderMJML({ layout, req: { isSubView: false } });
|
|
521
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;">Gradient Background</div></mj-raw></mj-section>`);
|
|
559
522
|
});
|
|
560
|
-
|
|
523
|
+
it("renders a layout with a rotated container", () => {
|
|
561
524
|
const layout = {
|
|
562
525
|
type: "container",
|
|
563
526
|
rotate: 45,
|
|
564
527
|
contents: [{ type: "blank", contents: "Rotated Content" }],
|
|
565
528
|
};
|
|
566
|
-
const result =
|
|
567
|
-
|
|
529
|
+
const result = renderMJML({ layout, req: { isSubView: false } });
|
|
530
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;">Rotated Content</div></mj-raw></mj-section>`);
|
|
568
531
|
});
|
|
569
|
-
|
|
532
|
+
it("renders a layout with a custom class and CSS", () => {
|
|
570
533
|
const layout = {
|
|
571
534
|
type: "container",
|
|
572
535
|
customClass: "custom-container",
|
|
573
536
|
customCSS: "border: 1px solid red;",
|
|
574
537
|
contents: [{ type: "blank", contents: "Custom Styled Content" }],
|
|
575
538
|
};
|
|
576
|
-
const result =
|
|
577
|
-
|
|
539
|
+
const result = renderMJML({ layout, req: { isSubView: false } });
|
|
540
|
+
expect(result.markup).toBe(`<mj-section><mj-raw><div style="text-align: left !important; font-size: 16px;">Custom Styled Content</div></mj-raw></mj-section>`);
|
|
578
541
|
});
|
|
579
542
|
});
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
543
|
+
describe("index", () => {
|
|
544
|
+
describe("post-bn", () => {
|
|
545
|
+
it("renders a basic post button", () => {
|
|
583
546
|
const result = post_btn("/submit", "Submit", "csrfToken123", {
|
|
584
547
|
btnClass: "btn-primary",
|
|
585
548
|
});
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
549
|
+
expect(result).toContain('<form action="/submit" method="post">');
|
|
550
|
+
expect(result).toContain('<input type="hidden" name="_csrf" value="csrfToken123">');
|
|
551
|
+
expect(result).toContain('<button type="submit" class=" btn btn-primary d-inline-block">Submit</button>');
|
|
552
|
+
expect(result).toContain("</form>");
|
|
590
553
|
});
|
|
591
|
-
|
|
554
|
+
it("renders a basic post button", () => {
|
|
592
555
|
const result = post_btn("/submit", "Submit", "csrfToken123", {
|
|
593
556
|
btnClass: "btn-primary",
|
|
594
557
|
});
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
558
|
+
expect(result).toContain('<form action="/submit" method="post">');
|
|
559
|
+
expect(result).toContain('<input type="hidden" name="_csrf" value="csrfToken123">');
|
|
560
|
+
expect(result).toContain('<button type="submit" class=" btn btn-primary d-inline-block">Submit</button>');
|
|
561
|
+
expect(result).toContain("</form>");
|
|
599
562
|
});
|
|
600
563
|
});
|
|
601
|
-
|
|
602
|
-
|
|
564
|
+
describe("post_delete_btn", () => {
|
|
565
|
+
it("renders a delete button with confirmation", () => {
|
|
603
566
|
const req = {
|
|
604
567
|
csrfToken: () => "csrfToken123",
|
|
605
568
|
__: (str) => str,
|
|
@@ -607,67 +570,67 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
607
570
|
};
|
|
608
571
|
const result = post_delete_btn("/delete", req);
|
|
609
572
|
const normalized = result.replace(/\s+/g, " ").trim();
|
|
610
|
-
|
|
573
|
+
expect(normalized).toBe(`<form action=\"/delete\" method=\"post\"><input type=\"hidden\" name=\"_csrf\" value=\"csrfToken123\"><button type=\"submit\" class=\"btn btn-danger btn-sm\" onclick=\"return confirm('Are you sure?')\"><i class=\"fas fa-trash-alt\"></i></button></form>`
|
|
611
574
|
.replace(/\s+/g, " ")
|
|
612
575
|
.trim());
|
|
613
576
|
});
|
|
614
577
|
});
|
|
615
|
-
|
|
616
|
-
|
|
578
|
+
describe("post_dropdown_item", () => {
|
|
579
|
+
it("renders a dropdown item with confirmation", () => {
|
|
617
580
|
const req = {
|
|
618
581
|
csrfToken: () => "csrfToken123",
|
|
619
582
|
__: (str) => str,
|
|
620
583
|
"Are you sure?": "Are you sure?",
|
|
621
584
|
};
|
|
622
585
|
const result = post_dropdown_item("/delete", "Delete", req, true);
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
586
|
+
expect(result).toContain('<a class="dropdown-item"');
|
|
587
|
+
expect(result).toContain("onclick=\"if(confirm('Are you sure?'))");
|
|
588
|
+
expect(result).toContain("$('#delete').submit()\">Delete</a>");
|
|
589
|
+
expect(result).toContain('<form id="delete" action="/delete" method="post">');
|
|
590
|
+
expect(result).toContain('<input type="hidden" name="_csrf" value="csrfToken123">');
|
|
628
591
|
});
|
|
629
592
|
});
|
|
630
|
-
|
|
631
|
-
|
|
593
|
+
describe("settingsDropdown", () => {
|
|
594
|
+
it("renders a settings dropdown", () => {
|
|
632
595
|
const result = settingsDropdown("dropdown1", "<a>Option 1</a>");
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
596
|
+
expect(result).toContain('<div class="dropdown">');
|
|
597
|
+
expect(result).toContain('<button class="btn btn-sm btn-outline-secondary"');
|
|
598
|
+
expect(result).toContain('<div class="dropdown-menu dropdown-menu-end"');
|
|
599
|
+
expect(result).toContain("<a>Option 1</a>");
|
|
637
600
|
});
|
|
638
601
|
});
|
|
639
|
-
|
|
640
|
-
|
|
602
|
+
describe("localeDate", () => {
|
|
603
|
+
it("renders a localized date", () => {
|
|
641
604
|
const date = new Date("2023-01-01T00:00:00Z");
|
|
642
605
|
const result = localeDate(date, {}, "en");
|
|
643
|
-
|
|
644
|
-
|
|
606
|
+
expect(result).toContain('<time datetime="2023-01-01T00:00:00.000Z"');
|
|
607
|
+
expect(result).toContain(">1/1/2023</time>");
|
|
645
608
|
});
|
|
646
|
-
|
|
609
|
+
it("renders a localized date with custom options", () => {
|
|
647
610
|
const date = new Date("2023-01-01T00:00:00Z");
|
|
648
611
|
const result = localeDate(date, { year: "numeric", month: "long", day: "numeric" }, "en");
|
|
649
|
-
|
|
650
|
-
|
|
612
|
+
expect(result).toContain('<time datetime="2023-01-01T00:00:00.000Z"');
|
|
613
|
+
expect(result).toContain(">January 1, 2023</time>");
|
|
651
614
|
});
|
|
652
615
|
});
|
|
653
616
|
});
|
|
654
|
-
|
|
655
|
-
|
|
617
|
+
describe("builder", () => {
|
|
618
|
+
it("renders the builder with default options", () => {
|
|
656
619
|
const options = { someOption: "value" };
|
|
657
620
|
const context = { someContent: "value" };
|
|
658
621
|
const action = "/submit";
|
|
659
622
|
const stepName = "step1";
|
|
660
623
|
const layout = { type: "container", contents: [] };
|
|
661
624
|
const csrfToken = "csrfToken123";
|
|
662
|
-
const result = (
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
});
|
|
670
|
-
|
|
625
|
+
const result = builder({ options, context, action, stepName, layout }, csrfToken);
|
|
626
|
+
expect(result).toContain('<div id="saltcorn-builder"></div>');
|
|
627
|
+
expect(result).toContain('<form action="/submit" method="post" id="scbuildform">');
|
|
628
|
+
expect(result).toContain('<input type="hidden" name="contextEnc"');
|
|
629
|
+
expect(result).toContain('<input type="hidden" name="stepName" value="step1">');
|
|
630
|
+
expect(result).toContain('<input type="hidden" name="_csrf" value="csrfToken123"');
|
|
631
|
+
expect(result).toContain("builder.renderBuilder(");
|
|
632
|
+
});
|
|
633
|
+
it("renders the builder with a version tag", () => {
|
|
671
634
|
const options = { someOptions: "value" };
|
|
672
635
|
const context = { someContext: "value" };
|
|
673
636
|
const action = "/submit";
|
|
@@ -675,11 +638,11 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
675
638
|
const layout = { type: "container", contents: [] };
|
|
676
639
|
const csrfToken = "csrfToken123";
|
|
677
640
|
const version_tag = "v1.0.0";
|
|
678
|
-
const result = (
|
|
679
|
-
|
|
680
|
-
|
|
641
|
+
const result = builder({ options, context, action, stepName, layout, version_tag }, csrfToken);
|
|
642
|
+
expect(result).toContain('<script src="/static_assets/v1.0.0/builder_bundle.js"></script>');
|
|
643
|
+
expect(result).toContain('<link rel="stylesheet" type="text/css" media="screen" href="/static_assets/v1.0.0/saltcorn-builder.css">');
|
|
681
644
|
});
|
|
682
|
-
|
|
645
|
+
it("renders the builder with custom mode", () => {
|
|
683
646
|
const options = { someOption: "value" };
|
|
684
647
|
const context = { someOptions: "value" };
|
|
685
648
|
const action = "/submit";
|
|
@@ -687,9 +650,9 @@ const { a, input, div, ul, text, text_attr, i, hr, genericElement } = tags;
|
|
|
687
650
|
const layout = { type: "container", contents: [] };
|
|
688
651
|
const csrfToken = "csrfToken123";
|
|
689
652
|
const mode = "edit";
|
|
690
|
-
const result = (
|
|
691
|
-
|
|
692
|
-
|
|
653
|
+
const result = builder({ options, context, action, stepName, layout, mode }, csrfToken);
|
|
654
|
+
expect(result).toContain("builder.renderBuilder(");
|
|
655
|
+
expect(result).toContain('"edit"');
|
|
693
656
|
});
|
|
694
657
|
});
|
|
695
658
|
//# sourceMappingURL=markup.test.js.map
|