@antelopejs/dms 0.7.21 → 0.8.1
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/CHANGELOG.md +55 -0
- package/dist/implementations/dms/resolver-timeout.d.ts +1 -0
- package/dist/implementations/dms/resolver-timeout.js +13 -3
- package/dist/implementations/dms/resolver-timeout.js.map +1 -1
- package/dist/implementations/dms-auth/account-emails.d.ts +4 -0
- package/dist/implementations/dms-auth/account-emails.js +62 -0
- package/dist/implementations/dms-auth/account-emails.js.map +1 -0
- package/dist/implementations/dms-auth/index.d.ts +1 -3
- package/dist/implementations/dms-auth/index.js +15 -61
- package/dist/implementations/dms-auth/index.js.map +1 -1
- package/dist/pages/settings/users/email-change.js +3 -4
- package/dist/pages/settings/users/email-change.js.map +1 -1
- package/dist/pages/settings/users/invites.js +1 -1
- package/dist/pages/settings/users/invites.js.map +1 -1
- package/dist/pages/settings/users/members.js +1 -1
- package/dist/pages/settings/users/members.js.map +1 -1
- package/dist/pages/settings/users/notifications.js +1 -0
- package/dist/pages/settings/users/notifications.js.map +1 -1
- package/dist/test/antelope.test.js +2 -1
- package/dist/test/antelope.test.js.map +1 -1
- package/dist/test/helpers/db.js +19 -11
- package/dist/test/helpers/db.js.map +1 -1
- package/dist/test/integration/auth/two-factor-codes.test.js +4 -2
- package/dist/test/integration/auth/two-factor-codes.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/dynamic-menu-hardening.test.js +8 -5
- package/dist/test/unit/implementations/dms/dynamic-menu-hardening.test.js.map +1 -1
- package/dist/test/unit/implementations/dms/layout-banners.test.js +20 -7
- package/dist/test/unit/implementations/dms/layout-banners.test.js.map +1 -1
- package/dist/test/unit/implementations/dms-html-render/built-in-emails.test.js +34 -0
- package/dist/test/unit/implementations/dms-html-render/built-in-emails.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/hook-handler-results.test.js +49 -0
- package/dist/test/unit/interfaces/dms/hook-handler-results.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms/page-topics.test.js +17 -0
- package/dist/test/unit/interfaces/dms/page-topics.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/confirm-dialog-secondary-action.test.js +2 -2
- package/dist/test/unit/interfaces/dms-base/confirm-dialog-secondary-action.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/query-response-delta.test.js +29 -0
- package/dist/test/unit/interfaces/dms-base/query-response-delta.test.js.map +1 -0
- package/dist/test/unit/interfaces/dms-base/resource-form.test.js +5 -0
- package/dist/test/unit/interfaces/dms-base/resource-form.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-form-redirect.test.js +12 -2
- package/dist/test/unit/interfaces/dms-base/table-view-form-redirect.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js +29 -4
- package/dist/test/unit/interfaces/dms-base/table-view-reduced-chrome.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-source-reorder.test.js +14 -11
- package/dist/test/unit/interfaces/dms-base/table-view-source-reorder.test.js.map +1 -1
- package/dist/test/unit/interfaces/dms-base/table-view-views.test.js +8 -5
- package/dist/test/unit/interfaces/dms-base/table-view-views.test.js.map +1 -1
- package/dist/test/unit/utils/email-subjects.test.js +27 -0
- package/dist/test/unit/utils/email-subjects.test.js.map +1 -0
- package/dist/utils/admin-invite-email.js +2 -4
- package/dist/utils/admin-invite-email.js.map +1 -1
- package/dist/utils/email-change-mail.d.ts +1 -1
- package/dist/utils/email-change-mail.js +11 -6
- package/dist/utils/email-change-mail.js.map +1 -1
- package/dist/utils/email-subjects.d.ts +3 -0
- package/dist/utils/email-subjects.js +32 -0
- package/dist/utils/email-subjects.js.map +1 -0
- package/dist/utils/export-jobs.js +15 -10
- package/dist/utils/export-jobs.js.map +1 -1
- package/frontend-vue/layers/dms-core/app/utils/url-interpolation.ts +29 -11
- package/frontend-vue/layers/dms-core/shared/types/app-config.ts +17 -0
- package/frontend-vue/layers/dms-layout/app/app.config.ts +5 -0
- package/frontend-vue/layers/dms-layout/app/build/components/layout/DashboardHeader.vue +18 -2
- package/frontend-vue/layers/dms-layout/app/build/components/layout/Footer.vue +16 -1
- package/frontend-vue/layers/dms-layout/app/build/composables/layout/useHeaderActionControls.ts +14 -0
- package/frontend-vue/layers/dms-layout/app/components/layout/HStack.vue +16 -0
- package/frontend-vue/layers/dms-layout/app/components/layout/VStack.vue +2 -0
- package/frontend-vue/layers/dms-layout/app/composables/useFooterLinks.ts +11 -1
- package/frontend-vue/layers/dms-layout/app/custom-pages/settings/roles.vue +1 -1
- package/frontend-vue/layers/dms-layout/app/emails/EmailAdminInvite.vue +1 -1
- package/frontend-vue/layers/dms-layout/app/emails/EmailChangeNotice.vue +13 -7
- package/frontend-vue/layers/dms-layout/app/emails/EmailChangeVerification.vue +18 -7
- package/frontend-vue/layers/dms-layout/app/emails/EmailExportReady.vue +23 -12
- package/frontend-vue/layers/dms-layout/app/emails/EmailResetPassword.vue +18 -7
- package/frontend-vue/layers/dms-layout/app/emails/EmailTwoFactor.vue +23 -4
- package/frontend-vue/layers/dms-layout/app/emails/EmailUserValidation.vue +18 -6
- package/frontend-vue/layers/dms-layout/app/emails/components/EmailOTP.vue +8 -2
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-en-GB.json +40 -0
- package/frontend-vue/layers/dms-layout/i18n/locales/layout-fr-FR.json +40 -0
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormFieldControl.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/build/components/form/FormLoadError.vue +11 -3
- package/frontend-vue/layers/dms-ui/app/build/composables/actions/useActionTargets.ts +27 -36
- package/frontend-vue/layers/dms-ui/app/build/composables/chart/apexTheme.ts +59 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/confirmDialogTexts.ts +27 -4
- package/frontend-vue/layers/dms-ui/app/build/composables/confirm/useActionConfirm.ts +10 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/data-types/registerDefaults.ts +0 -5
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formEntryOrder.ts +23 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formFooter.ts +19 -15
- package/frontend-vue/layers/dms-ui/app/build/composables/form/formRecordLoad.ts +26 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/page/pageUrlValues.ts +41 -0
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/registerDefaultFunctions.ts +2 -2
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableRows.ts +3 -5
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewConfig.ts +7 -12
- package/frontend-vue/layers/dms-ui/app/build/composables/table-view/useTableViewRowActions.ts +3 -3
- package/frontend-vue/layers/dms-ui/app/build/utils/link.ts +7 -3
- package/frontend-vue/layers/dms-ui/app/build/utils/urlVariables.ts +32 -9
- package/frontend-vue/layers/dms-ui/app/components/activity-feed/ActivityFeed.vue +8 -1
- package/frontend-vue/layers/dms-ui/app/components/banner/Banner.vue +9 -4
- package/frontend-vue/layers/dms-ui/app/components/blocks/BannerBlock.vue +5 -11
- package/frontend-vue/layers/dms-ui/app/components/blocks/NavCardGridBlock.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/chart/ApexChartHost.vue +32 -1
- package/frontend-vue/layers/dms-ui/app/components/check-list/CheckList.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/form/Form.vue +12 -2
- package/frontend-vue/layers/dms-ui/app/components/form/components/Cascader.vue +7 -3
- package/frontend-vue/layers/dms-ui/app/components/form/components/File.vue +7 -0
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputAddress.vue +4 -1
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputCode.vue +4 -2
- package/frontend-vue/layers/dms-ui/app/components/form/components/InputSecret.vue +3 -2
- package/frontend-vue/layers/dms-ui/app/components/form/components/Relation.vue +4 -1
- package/frontend-vue/layers/dms-ui/app/components/grid/GridRow.vue +14 -6
- package/frontend-vue/layers/dms-ui/app/components/grid/columns.ts +52 -3
- package/frontend-vue/layers/dms-ui/app/components/key-value-list/KeyValueList.vue +2 -1
- package/frontend-vue/layers/dms-ui/app/components/list-row/ListRow.vue +9 -2
- package/frontend-vue/layers/dms-ui/app/components/save-bar/InstantSaveBadge.vue +13 -5
- package/frontend-vue/layers/dms-ui/app/components/save-bar/SaveBar.vue +1 -1
- package/frontend-vue/layers/dms-ui/app/components/stat-group/StatGroup.vue +3 -2
- package/frontend-vue/layers/dms-ui/app/components/table-view/CascaderPath.vue +53 -31
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexPlotOptions.ts +15 -4
- package/frontend-vue/layers/dms-ui/app/composables/chart/apexYRange.ts +123 -0
- package/frontend-vue/layers/dms-ui/app/composables/chart/useApexChart.ts +49 -49
- package/frontend-vue/layers/dms-ui/app/composables/chart/useChartTheme.ts +20 -1
- package/frontend-vue/layers/dms-ui/app/composables/confirm/types.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/composables/form/types/props.ts +2 -0
- package/frontend-vue/layers/dms-ui/app/composables/form/useForm.ts +8 -6
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/action-target.ts +1 -1
- package/frontend-vue/layers/dms-ui/app/composables/table-view/types/config.ts +3 -5
- package/frontend-vue/layers/dms-ui/app/utils/bannerToneIcons.ts +13 -0
- package/frontend-vue/layers/dms-ui/app/utils/cascader.ts +26 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-en-GB.json +4 -0
- package/frontend-vue/layers/dms-ui/i18n/locales/ui-fr-FR.json +4 -0
- package/frontend-vue/package.json +1 -1
- package/frontend-vue/pnpm-lock.yaml +5 -5
- package/frontend-vue/tests/activity-feed-fill-height.test.ts +7 -0
- package/frontend-vue/tests/banner-tone-icon.test.ts +55 -0
- package/frontend-vue/tests/builtin-emails.test.ts +141 -0
- package/frontend-vue/tests/cascader.test.ts +27 -0
- package/frontend-vue/tests/chart-auto-y-range.test.ts +25 -9
- package/frontend-vue/tests/chart-colors.test.ts +8 -0
- package/frontend-vue/tests/chart-resize-after-animation.test.ts +100 -0
- package/frontend-vue/tests/chart-type-defaults.test.ts +128 -0
- package/frontend-vue/tests/check-list-marker.test.ts +58 -0
- package/frontend-vue/tests/confirm-from.test.ts +1 -1
- package/frontend-vue/tests/confirm-secondary-action.test.ts +2 -2
- package/frontend-vue/tests/context-links.test.ts +2 -2
- package/frontend-vue/tests/custom-action-confirm-from.test.ts +2 -2
- package/frontend-vue/tests/download-action-target.test.ts +2 -2
- package/frontend-vue/tests/file-drop-prompt.test.ts +72 -0
- package/frontend-vue/tests/footer-config.test.ts +135 -0
- package/frontend-vue/tests/form-actions.test.ts +7 -0
- package/frontend-vue/tests/form-enclosing-form.test.ts +0 -21
- package/frontend-vue/tests/form-entry-order.test.ts +45 -0
- package/frontend-vue/tests/form-footer-kind.test.ts +11 -6
- package/frontend-vue/tests/form-load-error.test.ts +38 -23
- package/frontend-vue/tests/grid-responsive-columns.test.ts +39 -31
- package/frontend-vue/tests/header-actions.test.ts +55 -9
- package/frontend-vue/tests/instant-save-badge.test.ts +11 -4
- package/frontend-vue/tests/list-row-truncate.test.ts +46 -0
- package/frontend-vue/tests/nuxt-ui-aria-labels.test.ts +1 -28
- package/frontend-vue/tests/period-live-pause.test.ts +0 -13
- package/frontend-vue/tests/period-max-days.test.ts +0 -14
- package/frontend-vue/tests/roles-name-errors.test.ts +2 -3
- package/frontend-vue/tests/row-side-panel.test.ts +0 -12
- package/frontend-vue/tests/save-bar.test.ts +15 -3
- package/frontend-vue/tests/save-status-error.test.ts +2 -2
- package/frontend-vue/tests/table-cell-wrap.test.ts +0 -12
- package/frontend-vue/tests/table-density-menu.test.ts +0 -21
- package/frontend-vue/tests/table-live-hold.test.ts +0 -44
- package/frontend-vue/tests/table-row-action-errors.test.ts +5 -5
- package/frontend-vue/tests/table-row-hover.test.ts +2 -12
- package/frontend-vue/tests/table-scroll-area.test.ts +0 -8
- package/frontend-vue/tests/table-view-card-props.test.ts +0 -17
- package/frontend-vue/tests/table-view-cards-reorder.test.ts +0 -16
- package/frontend-vue/tests/table-view-grouped.test.ts +0 -55
- package/frontend-vue/tests/table-view-pinned-rows.test.ts +0 -15
- package/frontend-vue/tests/table-view-record-link.test.ts +0 -17
- package/frontend-vue/tests/table-view-refresh.test.ts +0 -17
- package/frontend-vue/tests/table-view-sources.test.ts +1 -1
- package/frontend-vue/tests/table-view-url-tab.test.ts +0 -14
- package/frontend-vue/tests/template-tokens.test.ts +235 -0
- package/frontend-vue/tests/tone.test.ts +0 -19
- package/frontend-vue/tests/url-interpolation.test.ts +6 -6
- package/package.json +6 -6
- package/skills/dms/SKILL.md +2 -1
- package/skills/dms-pages/REFERENCE.md +2 -2
- package/skills/dms-project/SKILL.md +0 -1
- package/dist/test/integration/auth/login.test.js +0 -57
- package/dist/test/integration/auth/login.test.js.map +0 -1
- package/dist/test/integration/auth/refresh.test.js +0 -59
- package/dist/test/integration/auth/refresh.test.js.map +0 -1
- package/dist/test/integration/auth/sessions.test.js +0 -58
- package/dist/test/integration/auth/sessions.test.js.map +0 -1
- package/dist/test/integration/auth/signup.test.js +0 -99
- package/dist/test/integration/auth/signup.test.js.map +0 -1
- package/dist/test/unit/skills/dms-dev-script.test.d.ts +0 -1
- package/dist/test/unit/skills/dms-dev-script.test.js +0 -137
- package/dist/test/unit/skills/dms-dev-script.test.js.map +0 -1
- package/frontend-vue/tests/form-reload-on-reopen.test.ts +0 -20
- package/frontend-vue/tests/icon-aria-hidden.test.ts +0 -29
- package/frontend-vue/tests/skeleton-paragraph.test.ts +0 -30
- package/frontend-vue/tests/tab-slot-spacing.test.ts +0 -29
- package/frontend-vue/tests/table-empty-body-viewport.test.ts +0 -25
- package/frontend-vue/tests/table-header-placement.test.ts +0 -21
- package/frontend-vue/tests/vue-inventory.test.ts +0 -107
- /package/dist/test/{integration/auth/login.test.d.ts → unit/implementations/dms-html-render/built-in-emails.test.d.ts} +0 -0
- /package/dist/test/{integration/auth/sessions.test.d.ts → unit/interfaces/dms/hook-handler-results.test.d.ts} +0 -0
- /package/dist/test/{integration/auth/refresh.test.d.ts → unit/interfaces/dms-base/query-response-delta.test.d.ts} +0 -0
- /package/dist/test/{integration/auth/signup.test.d.ts → unit/utils/email-subjects.test.d.ts} +0 -0
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const chai_1 = require("chai");
|
|
4
|
-
const db_1 = require("../../helpers/db");
|
|
5
|
-
const fixtures_1 = require("../../helpers/fixtures");
|
|
6
|
-
const http_1 = require("../../helpers/http");
|
|
7
|
-
const SIGNUP_URL = "/api/auth/signup";
|
|
8
|
-
const VALID_PASSWORD = "TestPassw0rd!";
|
|
9
|
-
const WEAK_PASSWORD = "weak";
|
|
10
|
-
const TEST_EMAIL = "signup-success@test.local";
|
|
11
|
-
const OTHER_EMAIL = "other@test.local";
|
|
12
|
-
const NAME = "Signup User";
|
|
13
|
-
const LANG = "en";
|
|
14
|
-
const EXPIRED_INVITE_MS = -1000;
|
|
15
|
-
const UNKNOWN_TOKEN = "00000000-0000-0000-0000-000000000000";
|
|
16
|
-
describe.skip("[integration] auth/signup", () => {
|
|
17
|
-
beforeEach(async () => {
|
|
18
|
-
await (0, db_1.resetDatabase)();
|
|
19
|
-
});
|
|
20
|
-
it("signs up a user with a valid invite and returns tokens", async () => {
|
|
21
|
-
const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
|
|
22
|
-
const client = (0, http_1.createClient)();
|
|
23
|
-
const response = await client.post(SIGNUP_URL, {
|
|
24
|
-
name: NAME,
|
|
25
|
-
email: TEST_EMAIL,
|
|
26
|
-
password: VALID_PASSWORD,
|
|
27
|
-
lang: LANG,
|
|
28
|
-
token: invite.token,
|
|
29
|
-
});
|
|
30
|
-
(0, chai_1.expect)(response.status).to.equal(200);
|
|
31
|
-
(0, chai_1.expect)(response.data.token_type).to.equal("Bearer");
|
|
32
|
-
(0, chai_1.expect)(response.data.access_token).to.be.a("string").and.not.empty;
|
|
33
|
-
(0, chai_1.expect)(response.data.refresh_token).to.be.a("string").and.not.empty;
|
|
34
|
-
(0, chai_1.expect)(response.data.user?.email).to.equal(TEST_EMAIL);
|
|
35
|
-
});
|
|
36
|
-
it("rejects signup with an unknown token with 400", async () => {
|
|
37
|
-
const client = (0, http_1.createClient)();
|
|
38
|
-
const response = await client.post(SIGNUP_URL, {
|
|
39
|
-
name: NAME,
|
|
40
|
-
email: TEST_EMAIL,
|
|
41
|
-
password: VALID_PASSWORD,
|
|
42
|
-
lang: LANG,
|
|
43
|
-
token: UNKNOWN_TOKEN,
|
|
44
|
-
});
|
|
45
|
-
(0, chai_1.expect)(response.status).to.equal(400);
|
|
46
|
-
});
|
|
47
|
-
it("rejects signup when body email does not match invite email with 400", async () => {
|
|
48
|
-
const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
|
|
49
|
-
const client = (0, http_1.createClient)();
|
|
50
|
-
const response = await client.post(SIGNUP_URL, {
|
|
51
|
-
name: NAME,
|
|
52
|
-
email: OTHER_EMAIL,
|
|
53
|
-
password: VALID_PASSWORD,
|
|
54
|
-
lang: LANG,
|
|
55
|
-
token: invite.token,
|
|
56
|
-
});
|
|
57
|
-
(0, chai_1.expect)(response.status).to.equal(400);
|
|
58
|
-
});
|
|
59
|
-
it("rejects signup when invite is expired with 400", async () => {
|
|
60
|
-
const invite = await (0, fixtures_1.seedUserInvite)({
|
|
61
|
-
email: TEST_EMAIL,
|
|
62
|
-
lifetimeMs: EXPIRED_INVITE_MS,
|
|
63
|
-
});
|
|
64
|
-
const client = (0, http_1.createClient)();
|
|
65
|
-
const response = await client.post(SIGNUP_URL, {
|
|
66
|
-
name: NAME,
|
|
67
|
-
email: TEST_EMAIL,
|
|
68
|
-
password: VALID_PASSWORD,
|
|
69
|
-
lang: LANG,
|
|
70
|
-
token: invite.token,
|
|
71
|
-
});
|
|
72
|
-
(0, chai_1.expect)(response.status).to.equal(400);
|
|
73
|
-
});
|
|
74
|
-
it("rejects signup with a malformed email with 400", async () => {
|
|
75
|
-
const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
|
|
76
|
-
const client = (0, http_1.createClient)();
|
|
77
|
-
const response = await client.post(SIGNUP_URL, {
|
|
78
|
-
name: NAME,
|
|
79
|
-
email: "not-an-email",
|
|
80
|
-
password: VALID_PASSWORD,
|
|
81
|
-
lang: LANG,
|
|
82
|
-
token: invite.token,
|
|
83
|
-
});
|
|
84
|
-
(0, chai_1.expect)(response.status).to.equal(400);
|
|
85
|
-
});
|
|
86
|
-
it("rejects signup with a weak password with 400", async () => {
|
|
87
|
-
const invite = await (0, fixtures_1.seedUserInvite)({ email: TEST_EMAIL });
|
|
88
|
-
const client = (0, http_1.createClient)();
|
|
89
|
-
const response = await client.post(SIGNUP_URL, {
|
|
90
|
-
name: NAME,
|
|
91
|
-
email: TEST_EMAIL,
|
|
92
|
-
password: WEAK_PASSWORD,
|
|
93
|
-
lang: LANG,
|
|
94
|
-
token: invite.token,
|
|
95
|
-
});
|
|
96
|
-
(0, chai_1.expect)(response.status).to.equal(400);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
//# sourceMappingURL=signup.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signup.test.js","sourceRoot":"","sources":["../../../../src/test/integration/auth/signup.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const node_child_process_1 = require("node:child_process");
|
|
4
|
-
const node_fs_1 = require("node:fs");
|
|
5
|
-
const node_os_1 = require("node:os");
|
|
6
|
-
const node_path_1 = require("node:path");
|
|
7
|
-
const node_util_1 = require("node:util");
|
|
8
|
-
const chai_1 = require("chai");
|
|
9
|
-
const PACKAGE_ROOT = (0, node_path_1.resolve)(__dirname, "..", "..", "..", "..");
|
|
10
|
-
const SCRIPT = (0, node_path_1.join)(PACKAGE_ROOT, "skills", "dms-dev", "scripts", "dms-dev.sh");
|
|
11
|
-
const SCRIPT_TIMEOUT_MS = 30_000;
|
|
12
|
-
const SUITE_TIMEOUT_MS = 90_000;
|
|
13
|
-
const STOP_GRACE_SECONDS = "1";
|
|
14
|
-
const READY_TIMEOUT_SECONDS = "15";
|
|
15
|
-
const PROJECT_PORTS = { first: 6110, second: 6120 };
|
|
16
|
-
const FAKE_BACKEND = `#!/usr/bin/env bash
|
|
17
|
-
mkdir -p .antelope
|
|
18
|
-
printf '{"pid": %s, "servers": {"api": {"endpoints": [{"protocol": "http", "host": "0.0.0.0", "port": %s}]}}}' "$$" "$FAKE_PORT" > .antelope/dev.json
|
|
19
|
-
sleep 300 &
|
|
20
|
-
echo "Server started, listening on http://localhost:$FAKE_PORT"
|
|
21
|
-
wait
|
|
22
|
-
`;
|
|
23
|
-
const FAKE_FRONTEND = `#!/usr/bin/env bash
|
|
24
|
-
trap '' TERM
|
|
25
|
-
sleep 300 &
|
|
26
|
-
echo "Server ready on http://localhost:$((FAKE_PORT + 1))"
|
|
27
|
-
wait
|
|
28
|
-
`;
|
|
29
|
-
const runProcess = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
30
|
-
function createProject(root, name, port) {
|
|
31
|
-
const dir = (0, node_path_1.join)(root, name);
|
|
32
|
-
(0, node_fs_1.mkdirSync)((0, node_path_1.join)(dir, "bin"), { recursive: true });
|
|
33
|
-
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "package.json"), "{}");
|
|
34
|
-
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "bin", "antelope-runner"), FAKE_BACKEND);
|
|
35
|
-
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(dir, "bin", "ajs-dms"), FAKE_FRONTEND);
|
|
36
|
-
(0, node_fs_1.chmodSync)((0, node_path_1.join)(dir, "bin", "antelope-runner"), 0o755);
|
|
37
|
-
(0, node_fs_1.chmodSync)((0, node_path_1.join)(dir, "bin", "ajs-dms"), 0o755);
|
|
38
|
-
return { dir, port };
|
|
39
|
-
}
|
|
40
|
-
async function runScript(project, command) {
|
|
41
|
-
const env = {
|
|
42
|
-
...process.env,
|
|
43
|
-
FAKE_PORT: String(project.port),
|
|
44
|
-
DMS_BACK_DIR: project.dir,
|
|
45
|
-
DMS_BACK_CMD: (0, node_path_1.join)(project.dir, "bin", "antelope-runner"),
|
|
46
|
-
DMS_FRONT_CMD: `${(0, node_path_1.join)(project.dir, "bin", "ajs-dms")} dev`,
|
|
47
|
-
DMS_BACK_LOG: (0, node_path_1.join)(project.dir, "back.log"),
|
|
48
|
-
DMS_FRONT_LOG: (0, node_path_1.join)(project.dir, "front.log"),
|
|
49
|
-
DMS_DEV_STOP_GRACE: STOP_GRACE_SECONDS,
|
|
50
|
-
DMS_DEV_TIMEOUT: READY_TIMEOUT_SECONDS,
|
|
51
|
-
};
|
|
52
|
-
try {
|
|
53
|
-
const { stdout, stderr } = await runProcess("bash", [SCRIPT, command], {
|
|
54
|
-
env,
|
|
55
|
-
timeout: SCRIPT_TIMEOUT_MS,
|
|
56
|
-
});
|
|
57
|
-
return { code: 0, output: stdout + stderr };
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
const failure = error;
|
|
61
|
-
return {
|
|
62
|
-
code: failure.code ?? 1,
|
|
63
|
-
output: `${failure.stdout ?? ""}${failure.stderr ?? ""}`,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function pidFile(project) {
|
|
68
|
-
return (0, node_path_1.join)(project.dir, ".antelope", "dms-dev.pid");
|
|
69
|
-
}
|
|
70
|
-
function recordedPids(project) {
|
|
71
|
-
return (0, node_fs_1.readFileSync)(pidFile(project), "utf8")
|
|
72
|
-
.trim()
|
|
73
|
-
.split("\n")
|
|
74
|
-
.map((line) => Number(line.split(" ")[1]));
|
|
75
|
-
}
|
|
76
|
-
function isAlive(pid) {
|
|
77
|
-
try {
|
|
78
|
-
process.kill(pid, 0);
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
describe("[unit] skills/dms-dev script", function () {
|
|
86
|
-
this.timeout(SUITE_TIMEOUT_MS);
|
|
87
|
-
let root;
|
|
88
|
-
let first;
|
|
89
|
-
let second;
|
|
90
|
-
beforeEach(() => {
|
|
91
|
-
root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "dms-dev-script-"));
|
|
92
|
-
first = createProject(root, "first", PROJECT_PORTS.first);
|
|
93
|
-
second = createProject(root, "second", PROJECT_PORTS.second);
|
|
94
|
-
});
|
|
95
|
-
afterEach(async () => {
|
|
96
|
-
await runScript(first, "stop");
|
|
97
|
-
await runScript(second, "stop");
|
|
98
|
-
(0, node_fs_1.rmSync)(root, { recursive: true, force: true });
|
|
99
|
-
});
|
|
100
|
-
it("reports the ports the servers announce", async () => {
|
|
101
|
-
const started = await runScript(first, "start");
|
|
102
|
-
(0, chai_1.expect)(started.code, started.output).to.equal(0);
|
|
103
|
-
(0, chai_1.expect)(started.output).to.contain(`backend ready on http://localhost:${PROJECT_PORTS.first}.`);
|
|
104
|
-
(0, chai_1.expect)(started.output).to.contain(`frontend ready on http://localhost:${PROJECT_PORTS.first + 1}.`);
|
|
105
|
-
});
|
|
106
|
-
it("stops only the processes of its own project", async () => {
|
|
107
|
-
await runScript(first, "start");
|
|
108
|
-
await runScript(second, "start");
|
|
109
|
-
const firstPids = recordedPids(first);
|
|
110
|
-
const secondPids = recordedPids(second);
|
|
111
|
-
const stopped = await runScript(first, "stop");
|
|
112
|
-
(0, chai_1.expect)(stopped.code, stopped.output).to.equal(0);
|
|
113
|
-
(0, chai_1.expect)(firstPids.filter(isAlive)).to.deep.equal([]);
|
|
114
|
-
(0, chai_1.expect)(secondPids.filter(isAlive)).to.deep.equal(secondPids);
|
|
115
|
-
(0, chai_1.expect)((0, node_fs_1.existsSync)(pidFile(first))).to.equal(false);
|
|
116
|
-
});
|
|
117
|
-
it("falls back to the project's directory when the pid file is gone", async () => {
|
|
118
|
-
await runScript(first, "start");
|
|
119
|
-
await runScript(second, "start");
|
|
120
|
-
const firstPids = recordedPids(first);
|
|
121
|
-
const secondPids = recordedPids(second);
|
|
122
|
-
(0, node_fs_1.rmSync)(pidFile(first));
|
|
123
|
-
const stopped = await runScript(first, "stop");
|
|
124
|
-
(0, chai_1.expect)(stopped.code, stopped.output).to.equal(0);
|
|
125
|
-
(0, chai_1.expect)(firstPids.filter(isAlive)).to.deep.equal([]);
|
|
126
|
-
(0, chai_1.expect)(secondPids.filter(isAlive)).to.deep.equal(secondPids);
|
|
127
|
-
});
|
|
128
|
-
it("fails fast when the server command dies right away", async () => {
|
|
129
|
-
(0, node_fs_1.rmSync)((0, node_path_1.join)(first.dir, "bin", "antelope-runner"));
|
|
130
|
-
const startedAt = Date.now();
|
|
131
|
-
const started = await runScript(first, "start");
|
|
132
|
-
(0, chai_1.expect)(started.code).to.equal(1);
|
|
133
|
-
(0, chai_1.expect)(started.output).to.contain("exited before becoming ready");
|
|
134
|
-
(0, chai_1.expect)(Date.now() - startedAt).to.be.below(SCRIPT_TIMEOUT_MS / 2);
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
//# sourceMappingURL=dms-dev-script.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dms-dev-script.test.js","sourceRoot":"","sources":["../../../../src/test/unit/skills/dms-dev-script.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
const formSource = readFileSync(
|
|
5
|
-
new URL("../layers/dms-ui/app/components/form/Form.vue", import.meta.url),
|
|
6
|
-
"utf8",
|
|
7
|
-
);
|
|
8
|
-
|
|
9
|
-
// The load of a form is cached under its component and page ids, which a
|
|
10
|
-
// drawer or modal reopened on the same row shares: the second opening showed
|
|
11
|
-
// the first one's values, stale if the row changed in between, and a save
|
|
12
|
-
// then wrote them back.
|
|
13
|
-
it("fetches its record again every time a form is mounted", () => {
|
|
14
|
-
const loadBlock = formSource.slice(
|
|
15
|
-
formSource.indexOf("if (props.fetchUrl) {"),
|
|
16
|
-
);
|
|
17
|
-
expect(loadBlock).toMatch(
|
|
18
|
-
/const formLoad = await useDmsAsyncData\([\s\S]*?onMounted\(\(\) => \{\s*formLoad\.status\.value = "idle";\s*\}\);/,
|
|
19
|
-
);
|
|
20
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
-
import { join, relative } from "node:path";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
const ICON_TAG = /<(?:UIcon|Icon)\b[^>]*?>/gs;
|
|
6
|
-
const STATIC_ARIA_HIDDEN = /(?<![:\w-])aria-hidden=/;
|
|
7
|
-
|
|
8
|
-
function walk(directory: string): string[] {
|
|
9
|
-
return readdirSync(directory).flatMap((name) => {
|
|
10
|
-
const path = join(directory, name);
|
|
11
|
-
return statSync(path).isDirectory() ? walk(path) : [path];
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe("icon aria-hidden bindings", () => {
|
|
16
|
-
// The icon hands its attributes to Iconify's component, whose `ariaHidden`
|
|
17
|
-
// prop is a Boolean: a static attribute reaches it as the string "true".
|
|
18
|
-
it("binds aria-hidden on icons as a boolean", () => {
|
|
19
|
-
const offenders = walk(join(process.cwd(), "layers"))
|
|
20
|
-
.filter((path) => path.endsWith(".vue"))
|
|
21
|
-
.flatMap((path) =>
|
|
22
|
-
[...readFileSync(path, "utf8").matchAll(ICON_TAG)]
|
|
23
|
-
.filter(([tag]) => STATIC_ARIA_HIDDEN.test(tag))
|
|
24
|
-
.map(() => relative(process.cwd(), path)),
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
expect(offenders).toEqual([]);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
-
import { join, relative } from "node:path";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
const PARAGRAPH = /<p\b[^>]*>(.*?)<\/p>/gs;
|
|
6
|
-
const SKELETON = /<USkeleton\b/;
|
|
7
|
-
|
|
8
|
-
function walk(directory: string): string[] {
|
|
9
|
-
return readdirSync(directory).flatMap((name) => {
|
|
10
|
-
const path = join(directory, name);
|
|
11
|
-
return statSync(path).isDirectory() ? walk(path) : [path];
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe("skeleton placement", () => {
|
|
16
|
-
// The skeleton renders a <div>. The browser's parser closes an open <p>
|
|
17
|
-
// before a <div>, so the server markup no longer matches the client tree
|
|
18
|
-
// and hydration reports a mismatch.
|
|
19
|
-
it("keeps skeletons out of paragraphs", () => {
|
|
20
|
-
const offenders = walk(join(process.cwd(), "layers"))
|
|
21
|
-
.filter((path) => path.endsWith(".vue"))
|
|
22
|
-
.flatMap((path) =>
|
|
23
|
-
[...readFileSync(path, "utf8").matchAll(PARAGRAPH)]
|
|
24
|
-
.filter(([, content]) => SKELETON.test(content ?? ""))
|
|
25
|
-
.map(() => relative(process.cwd(), path)),
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
expect(offenders).toEqual([]);
|
|
29
|
-
});
|
|
30
|
-
});
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
/** The room the page leaves between its blocks. */
|
|
5
|
-
const BLOCK_SPACING = "space-y-6";
|
|
6
|
-
|
|
7
|
-
const sourceOf = (file: string) =>
|
|
8
|
-
readFileSync(new URL(`../layers/${file}`, import.meta.url), "utf8");
|
|
9
|
-
|
|
10
|
-
// A tab holding two blocks stacked them edge to edge, while the page spaces
|
|
11
|
-
// the same two blocks placed outside a tab.
|
|
12
|
-
it("spaces the blocks of a tab the way the page spaces its own", () => {
|
|
13
|
-
expect(sourceOf("dms-layout/app/pages/[...slug].vue")).toContain(
|
|
14
|
-
`dms-page-stack ${BLOCK_SPACING}`,
|
|
15
|
-
);
|
|
16
|
-
expect(sourceOf("dms-ui/app/components/tab/Tab.vue")).toMatch(
|
|
17
|
-
new RegExp(
|
|
18
|
-
`<div class="[^"]*\\b${BLOCK_SPACING}\\b[^"]*"[^>]*>\\s*<slot :name="item.slot" />`,
|
|
19
|
-
),
|
|
20
|
-
);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// A guard holding two blocks drew them edge to edge: the page spaces its own
|
|
24
|
-
// wrapper, not the blocks inside it.
|
|
25
|
-
it("spaces the blocks of a guard the way the page spaces its own", () => {
|
|
26
|
-
expect(sourceOf("dms-ui/app/components/guard/Guard.vue")).toMatch(
|
|
27
|
-
new RegExp(`<div class="[^"]*\\b${BLOCK_SPACING}\\b[^"]*" data-dms-guard>`),
|
|
28
|
-
);
|
|
29
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
const tableSource = readFileSync(
|
|
6
|
-
resolve(__dirname, "../layers/dms-ui/app/build/components/table/Table.vue"),
|
|
7
|
-
"utf8",
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
describe("table empty body", () => {
|
|
11
|
-
it("centres on the visible part of a table wider than its card", () => {
|
|
12
|
-
expect(tableSource).toMatch(
|
|
13
|
-
/emptyBody:\s*"sticky start-0 w-\[var\(--dms-table-viewport,auto\)\]"/,
|
|
14
|
-
);
|
|
15
|
-
expect(tableSource).toMatch(
|
|
16
|
-
/<div :class="uiTable\.emptyBody\(\)">\s*<TableEmpty/,
|
|
17
|
-
);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it("knows the visible width of every table, not only expandable ones", () => {
|
|
21
|
-
expect(tableSource).toMatch(
|
|
22
|
-
/"--dms-table-viewport":\s*tableViewportWidth\.value > 0/,
|
|
23
|
-
);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
|
-
import { resolve } from "node:path";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
const tableSource = readFileSync(
|
|
6
|
-
resolve(__dirname, "../layers/dms-ui/app/build/components/table/Table.vue"),
|
|
7
|
-
"utf8",
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
describe("Table buttons placed in the page header", () => {
|
|
11
|
-
it("leaves them out of the toolbar", () => {
|
|
12
|
-
expect(tableSource).toMatch(
|
|
13
|
-
/\(props\.customButtons \?\? \[\]\)\.filter\(\s*\(button\) => button\.placement !== HEADER_PLACEMENT,\s*\)/,
|
|
14
|
-
);
|
|
15
|
-
expect(tableSource).toMatch(
|
|
16
|
-
/add\.isEnabled && add\.placement !== HEADER_PLACEMENT/,
|
|
17
|
-
);
|
|
18
|
-
expect(tableSource).toContain(':can-add-row="canAddFromToolbar"');
|
|
19
|
-
expect(tableSource).not.toContain("button.hidden");
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
|
-
import { join, relative } from "node:path";
|
|
3
|
-
import { describe, expect, it } from "vitest";
|
|
4
|
-
|
|
5
|
-
const EXPECTED_VUE_FILES = 278;
|
|
6
|
-
|
|
7
|
-
function walk(directory: string): string[] {
|
|
8
|
-
return readdirSync(directory).flatMap((name) => {
|
|
9
|
-
const path = join(directory, name);
|
|
10
|
-
return statSync(path).isDirectory() ? walk(path) : [path];
|
|
11
|
-
});
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function ownership(path: string): string | undefined {
|
|
15
|
-
const owners: Array<[RegExp, string]> = [
|
|
16
|
-
[/\/app\/(?:components|build\/components)\/.*\.vue$/, "component"],
|
|
17
|
-
[/\/app\/custom-pages\/.*\.vue$/, "custom-page"],
|
|
18
|
-
[/\/app\/pages\/.*\.vue$/, "dynamic-page"],
|
|
19
|
-
[/\/app\/custom-layouts\/.*\.vue$/, "layout"],
|
|
20
|
-
[/\/app\/error\.vue$/, "inertia-error-page"],
|
|
21
|
-
[/\/app\/emails\/.*\.vue$/, "server-email-template"],
|
|
22
|
-
];
|
|
23
|
-
// Forward slashes on every OS, so the patterns also match Windows paths.
|
|
24
|
-
const normalized = path.replaceAll("\\", "/");
|
|
25
|
-
return owners.find(([pattern]) => pattern.test(normalized))?.[1];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
describe("Vue source inventory", () => {
|
|
29
|
-
it("contains only Vue frontend source files", () => {
|
|
30
|
-
const files = walk(join(process.cwd(), "layers")).map((path) =>
|
|
31
|
-
path.replaceAll("\\", "/"),
|
|
32
|
-
);
|
|
33
|
-
expect(files.filter((path) => path.includes("/server/"))).toEqual([]);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("assigns every Vue file an explicit runtime owner", () => {
|
|
37
|
-
const files = walk(join(process.cwd(), "layers"))
|
|
38
|
-
.filter((path) => path.endsWith(".vue"))
|
|
39
|
-
.map((path) => relative(process.cwd(), path));
|
|
40
|
-
expect(files).toHaveLength(EXPECTED_VUE_FILES);
|
|
41
|
-
expect(files.filter((path) => !ownership(path))).toEqual([]);
|
|
42
|
-
expect(
|
|
43
|
-
files.filter((path) => ownership(path) === "server-email-template"),
|
|
44
|
-
).toHaveLength(10);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("exposes entries for the frontend adapter", () => {
|
|
48
|
-
const root = process.cwd();
|
|
49
|
-
const frontendModule = readFileSync(join(root, "dms.frontend.ts"), "utf8");
|
|
50
|
-
|
|
51
|
-
expect(frontendModule).toContain(
|
|
52
|
-
'import "./layers/dms-layout/app/assets/css/main.css"',
|
|
53
|
-
);
|
|
54
|
-
expect(frontendModule).toContain('"./layers/**/app/custom-pages/**/*.vue"');
|
|
55
|
-
expect(frontendModule).toContain(
|
|
56
|
-
'"./layers/**/app/custom-layouts/**/*.vue"',
|
|
57
|
-
);
|
|
58
|
-
expect(frontendModule).toContain('"./layers/**/app/error.vue"');
|
|
59
|
-
expect(frontendModule).toContain('componentPrefix: "Dms"');
|
|
60
|
-
expect(frontendModule).toContain(
|
|
61
|
-
"sdk.registerComponent(pascalCase(name), component)",
|
|
62
|
-
);
|
|
63
|
-
for (const [name, alias] of [
|
|
64
|
-
["ActivityFeed", "ActivityFeedBlock"],
|
|
65
|
-
["Section", "SectionBlock"],
|
|
66
|
-
["FieldRow", "FieldRowBlock"],
|
|
67
|
-
]) {
|
|
68
|
-
expect(frontendModule).toContain(`${name}: "${alias}"`);
|
|
69
|
-
}
|
|
70
|
-
expect(frontendModule).toContain('.replace(/\\/index$/, "")');
|
|
71
|
-
expect(frontendModule).toContain(
|
|
72
|
-
"sdk.registerErrorPage(lazyComponent(loader), loader)",
|
|
73
|
-
);
|
|
74
|
-
|
|
75
|
-
const entries = walk(join(root, "layers"))
|
|
76
|
-
.map((path) => path.replaceAll("\\", "/"))
|
|
77
|
-
.filter(
|
|
78
|
-
(path) =>
|
|
79
|
-
path.includes("/app/custom-pages/") ||
|
|
80
|
-
path.endsWith("/app/error.vue"),
|
|
81
|
-
);
|
|
82
|
-
expect(entries).not.toHaveLength(0);
|
|
83
|
-
expect(
|
|
84
|
-
entries.every((path) => path.endsWith(".vue") && statSync(path).isFile()),
|
|
85
|
-
).toBe(true);
|
|
86
|
-
expect(
|
|
87
|
-
statSync(
|
|
88
|
-
join(root, "layers/dms-layout/app/custom-layouts/DefaultLayout.vue"),
|
|
89
|
-
).isFile(),
|
|
90
|
-
).toBe(true);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it("registers lazy components and reports deterministic name collisions", () => {
|
|
94
|
-
const frontendModule = readFileSync(
|
|
95
|
-
join(process.cwd(), "dms.frontend.ts"),
|
|
96
|
-
"utf8",
|
|
97
|
-
);
|
|
98
|
-
expect(frontendModule).toContain("defineAsyncComponent");
|
|
99
|
-
expect(frontendModule).toContain("sortedEntries(components)");
|
|
100
|
-
expect(frontendModule).toContain(
|
|
101
|
-
"Duplicate component name ${name}: ${previousPath}, ${path}",
|
|
102
|
-
);
|
|
103
|
-
expect(frontendModule).not.toMatch(
|
|
104
|
-
/components\|build\/components}[\s\S]*eager: true/,
|
|
105
|
-
);
|
|
106
|
-
});
|
|
107
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/test/{integration/auth/signup.test.d.ts → unit/utils/email-subjects.test.d.ts}
RENAMED
|
File without changes
|