@nutin/cli 2.1.1 → 3.0.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/CHANGELOG.md +268 -0
- package/README.md +13 -5
- package/bin/add-feature.mjs +1 -1
- package/bin/cli.mjs +1 -1
- package/bin/create-app.mjs +1 -1
- package/bin/update-app.mjs +1 -1
- package/lib/index.mjs +6 -2
- package/lib/src/add-feature/base-template-patcher.mjs +139 -0
- package/lib/src/add-feature/feature-adder.mjs +20 -9
- package/lib/src/add-feature/feature-context-builder.mjs +1 -0
- package/lib/src/add-feature/nutin-config-updater.mjs +34 -8
- package/lib/src/add-feature/package-json-updater.mjs +7 -9
- package/lib/src/common/feature-registry.mjs +4 -0
- package/lib/src/common/file-generator.mjs +25 -3
- package/lib/src/common/git.mjs +31 -0
- package/lib/src/common/meta-bootstrap-prompt.mjs +28 -2
- package/lib/src/common/package-json-helper.mjs +14 -4
- package/lib/src/common/project-meta.mjs +2 -2
- package/lib/src/common/template-compiler.mjs +2 -0
- package/lib/src/common/transpile-ts.mjs +94 -0
- package/lib/src/create-app/context-builder.mjs +1 -0
- package/lib/src/create-app/git-manager.mjs +12 -2
- package/lib/src/create-app/json-manager.mjs +21 -18
- package/lib/src/create-app/new-app-prompt.mjs +4 -2
- package/lib/src/create-app/success-message.mjs +1 -1
- package/lib/src/update-app/conflict-report-writer.mjs +33 -21
- package/lib/src/update-app/json-drift.mjs +54 -0
- package/lib/src/update-app/project-updater.mjs +123 -14
- package/lib/src/update-app/template-differ.mjs +5 -5
- package/lib/src/update-app/three-way-merge.mjs +42 -0
- package/lib/src/update-app/update-context-builder.mjs +1 -0
- package/lib/src/update-app/update-summary-printer.mjs +10 -2
- package/package.json +9 -8
- package/templates/base/AGENTS.md.hbs +42 -41
- package/templates/base/GETTING_STARTED.md.hbs +26 -20
- package/templates/base/README.md.hbs +7 -4
- package/templates/base/src/app/globals.d.ts.hbs +6 -3
- package/templates/base/src/app/guards.ts.hbs +1 -3
- package/templates/base/src/app/main.ts.hbs +2 -9
- package/templates/base/src/app/routes.ts.hbs +7 -2
- package/templates/base/src/app/views/home/home.view.html.hbs +1 -1
- package/templates/base/src/app/views/home/home.view.ts.hbs +2 -2
- package/templates/base/src/app/views/not-found/not-found.view.ts.hbs +2 -2
- package/templates/base/src/core/base-classes/base-component/base-component.test.js.hbs +461 -1
- package/templates/base/src/core/base-classes/base-component/base-component.ts.hbs +39 -48
- package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.test.js.hbs +36 -1
- package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.ts.hbs +47 -77
- package/templates/base/src/core/base-classes/base-component/helpers/children.helper.test.js.hbs +286 -24
- package/templates/base/src/core/base-classes/base-component/helpers/children.helper.ts.hbs +144 -26
- package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.test.js.hbs +66 -4
- package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.ts.hbs +135 -75
- package/templates/base/src/core/base-classes/base-component/helpers/event.helper.test.js.hbs +85 -4
- package/templates/base/src/core/base-classes/base-component/helpers/event.helper.ts.hbs +93 -54
- package/templates/base/src/core/base-classes/base-component/helpers/html.helper.test.js.hbs +404 -0
- package/templates/base/src/core/base-classes/base-component/helpers/html.helper.ts.hbs +242 -0
- package/templates/base/src/core/base-classes/base-component/helpers/i18n.helper.test.js.hbs +70 -1
- package/templates/base/src/core/base-classes/base-component/helpers/i18n.helper.ts.hbs +54 -15
- package/templates/base/src/core/base-classes/base-component/helpers/pipe.helper.test.js.hbs +12 -1
- package/templates/base/src/core/base-classes/base-component/helpers/pipe.helper.ts.hbs +39 -36
- package/templates/base/src/core/base-classes/base-component/helpers/preservation.helper.test.js.hbs +179 -0
- package/templates/base/src/core/base-classes/base-component/helpers/preservation.helper.ts.hbs +93 -0
- package/templates/base/src/core/base-classes/base-component/helpers/security.helper.test.js.hbs +135 -17
- package/templates/base/src/core/base-classes/base-component/helpers/security.helper.ts.hbs +199 -81
- package/templates/base/src/core/base-classes/base-component/helpers/token.helper.test.js.hbs +40 -23
- package/templates/base/src/core/base-classes/base-component/helpers/token.helper.ts.hbs +67 -65
- package/templates/base/src/core/base-classes/component/component.test.js.hbs +17 -17
- package/templates/base/src/core/base-classes/component/component.ts.hbs +8 -41
- package/templates/base/src/core/base-classes/component/helpers/config.helper.test.js.hbs +1 -1
- package/templates/base/src/core/base-classes/component/helpers/config.helper.ts.hbs +37 -39
- package/templates/base/src/core/base-classes/component/helpers/data-binding.helper.test.js.hbs +14 -1
- package/templates/base/src/core/base-classes/component/helpers/data-binding.helper.ts.hbs +33 -31
- package/templates/base/src/core/base-classes/service/service.test.js.hbs +32 -0
- package/templates/base/src/core/base-classes/service/service.ts.hbs +21 -13
- package/templates/base/src/core/base-classes/view/view.test.js.hbs +4 -0
- package/templates/base/src/core/base-classes/view/view.ts.hbs +11 -8
- package/templates/base/src/core/index.ts.hbs +4 -2
- package/templates/base/src/core/internals.d.ts.hbs +199 -20
- package/templates/base/src/core/services/event-bus/event-bus.test.js.hbs +18 -0
- package/templates/base/src/core/services/event-bus/event-bus.ts.hbs +26 -25
- package/templates/base/src/core/services/event-bus/lifecycle.facade.ts.hbs +3 -3
- package/templates/base/src/core/services/event-bus/navigation.facade.ts.hbs +3 -3
- package/templates/base/src/core/services/globals/globals.ts.hbs +7 -32
- package/templates/base/src/core/services/http-client/helpers/http-builder.helper.test.js.hbs +133 -50
- package/templates/base/src/core/services/http-client/helpers/http-builder.helper.ts.hbs +147 -39
- package/templates/base/src/core/services/http-client/helpers/http-manager.helper.test.js.hbs +75 -19
- package/templates/base/src/core/services/http-client/helpers/http-manager.helper.ts.hbs +73 -47
- package/templates/base/src/core/services/http-client/http-client.test.js.hbs +339 -232
- package/templates/base/src/core/services/http-client/http-client.ts.hbs +37 -25
- package/templates/base/src/core/services/i18n/i18n.test.js.hbs +57 -16
- package/templates/base/src/core/services/i18n/i18n.ts.hbs +42 -42
- package/templates/base/src/core/services/i18n/languages.ts.hbs +0 -2
- package/templates/base/src/core/services/pipe-registry/pipe-registry.ts.hbs +4 -6
- package/templates/base/src/core/services/pipe-registry/pipes.test.js.hbs +10 -0
- package/templates/base/src/core/services/pipe-registry/pipes.ts.hbs +4 -2
- package/templates/base/src/core/services/router/helpers/navigation-manager.helper.test.js.hbs +183 -4
- package/templates/base/src/core/services/router/helpers/navigation-manager.helper.ts.hbs +207 -84
- package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.test.js.hbs +26 -27
- package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.ts.hbs +38 -60
- package/templates/base/src/core/services/router/helpers/view-render-manager.helper.test.js.hbs +4 -4
- package/templates/base/src/core/services/router/helpers/view-render-manager.helper.ts.hbs +30 -30
- package/templates/base/src/core/services/router/router.test.js.hbs +306 -0
- package/templates/base/src/core/services/router/router.ts.hbs +113 -53
- package/templates/base/tools/builder/builder.config.js.hbs +6 -0
- package/templates/base/tools/builder/builder.js.hbs +18 -6
- package/templates/base/tools/builder/core/app/compile-ts.js.hbs +81 -6
- package/templates/base/tools/builder/core/app/copy-static.js.hbs +12 -1
- package/templates/base/tools/builder/core/app/handler-refs.js.hbs +114 -0
- package/templates/base/tools/builder/core/app/handler-refs.test.js.hbs +70 -0
- package/templates/base/tools/builder/core/app/paths.js.hbs +17 -0
- package/templates/base/tools/builder/core/app/route-keys.js.hbs +47 -0
- package/templates/base/tools/builder/core/app/route-keys.test.js.hbs +97 -0
- package/templates/base/tools/builder/core/app/ts-errors.js.hbs +58 -0
- package/templates/base/tools/builder/core/app/ts-errors.test.js.hbs +84 -0
- package/templates/base/tools/builder/core/app/validate-routes.js.hbs +21 -55
- package/templates/base/tools/builder/core/finalize-build.js.hbs +6 -0
- package/templates/base/tools/builder/core/html-index/validate-html.js.hbs +10 -2
- package/templates/base/tools/builder/core/html-templates/merge-templates.js.hbs +111 -23
- package/templates/base/tools/builder/core/html-templates/minify-templates.js.hbs +8 -0
- package/templates/base/tools/builder/core/html-templates/process-html-templates.js.hbs +5 -3
- package/templates/base/tools/builder/core/html-templates/template-literal.js.hbs +193 -0
- package/templates/base/tools/builder/core/html-templates/template-literal.test.js.hbs +69 -0
- package/templates/base/tools/builder/core/i18n/build-i18n.js.hbs +14 -6
- package/templates/base/tools/builder/core/prod-bundle/bundle-options.js.hbs +82 -0
- package/templates/base/tools/builder/core/prod-bundle/bundle-options.test.js.hbs +65 -0
- package/templates/base/tools/builder/core/prod-bundle/compress-files.js.hbs +6 -6
- package/templates/base/tools/builder/core/prod-bundle/esbuild.js.hbs +15 -7
- package/templates/base/tools/builder/core/prod-bundle/hash-files.js.hbs +4 -4
- package/templates/base/tools/builder/core/seo/generate-robots-txt.js.hbs +31 -13
- package/templates/base/tools/builder/core/seo/generate-robots-txt.test.js.hbs +48 -0
- package/templates/base/tools/builder/core/seo/generate-seo-files.js.hbs +3 -3
- package/templates/base/tools/builder/core/seo/generate-seo-html.js.hbs +43 -13
- package/templates/base/tools/builder/core/seo/generate-sitemap-xml.js.hbs +22 -7
- package/templates/base/tools/builder/core/seo/generate-sitemap-xml.test.js.hbs +30 -0
- package/templates/base/tools/builder/core/seo/html-substitutions.js.hbs +28 -21
- package/templates/base/tools/builder/core/seo/html-substitutions.test.js.hbs +45 -0
- package/templates/base/tools/builder/core/seo/route-output.js.hbs +24 -6
- package/templates/base/tools/builder/core/seo/route-output.test.js.hbs +31 -0
- package/templates/base/tools/builder/core/seo/seo-routes.js.hbs +29 -0
- package/templates/base/tools/builder/core/seo/seo-routes.test.js.hbs +21 -0
- package/templates/base/tools/builder/core/seo/ssr/ssr-bundle.js.hbs +6 -7
- package/templates/base/tools/builder/core/seo/ssr/ssr-polyfills.js.hbs +34 -5
- package/templates/base/tools/builder/core/seo/ssr/ssr-polyfills.test.js.hbs +48 -0
- package/templates/base/tools/builder/core/seo/ssr/ssr-render.js.hbs +24 -11
- package/templates/base/tools/builder/core/styles/sass.js.hbs +3 -2
- package/templates/base/tools/builder/core/styles/tailwind.js.hbs +19 -59
- package/templates/base/tools/dev/dev-serve.js.hbs +30 -5
- package/templates/base/tools/dev/serve.js.hbs +152 -22
- package/templates/base/tools/dev/watcher.js.hbs +34 -3
- package/templates/base/tools/generator/generator.js.hbs +1 -1
- package/templates/base/tools/generator/handle-file.js.hbs +4 -2
- package/templates/base/tools/generator/handle-file.test.js.hbs +3 -3
- package/templates/base/tools/generator/templates/component/component.template.js.hbs +3 -3
- package/templates/base/tools/generator/templates/component/component.template.test.js.hbs +3 -3
- package/templates/base/tools/generator/templates/service/service.template.js.hbs +1 -1
- package/templates/base/tools/generator/templates/service/service.template.test.js.hbs +1 -1
- package/templates/base/tools/generator/templates/view/view.template.js.hbs +2 -2
- package/templates/base/tools/generator/templates/view/view.template.test.js.hbs +2 -2
- package/templates/base/tools/testin-nutin/core/coverage/write-uncovered-report.js.hbs +1 -1
- package/templates/base/tools/testin-nutin/core/globals/assertion-lib.js.hbs +2 -2
- package/templates/base/tools/testin-nutin/core/{tests/assertions.test.js.hbs → globals/assertion-lib.test.js.hbs} +6 -0
- package/templates/base/tools/testin-nutin/core/globals/register-test-globals.js.hbs +6 -7
- package/templates/base/tools/testin-nutin/core/{tests/globals-each-all.test.js.hbs → globals/register-test-globals.test.js.hbs} +12 -0
- package/templates/base/tools/testin-nutin/core/printer.js.hbs +10 -4
- package/templates/base/tools/testin-nutin/core/queue/test-queue.js.hbs +8 -8
- package/templates/base/tools/testin-nutin/mocks/mock-event-bus.js.hbs +27 -25
- package/templates/base/tools/testin-nutin/mocks/mock-event-bus.test.js.hbs +30 -22
- package/templates/base/tools/testin-nutin/mocks/mock-http-client.js.hbs +7 -10
- package/templates/base/tools/testin-nutin/mocks/mock-http-client.test.js.hbs +12 -0
- package/templates/base/tools/testin-nutin/mocks/mock-i18n.js.hbs +47 -22
- package/templates/base/tools/testin-nutin/mocks/mock-i18n.test.js.hbs +47 -26
- package/templates/base/tools/testin-nutin/mocks/mock-router.js.hbs +19 -11
- package/templates/base/tools/testin-nutin/mocks/mock-router.test.js.hbs +24 -7
- package/templates/base/tools/testin-nutin/runner.js.hbs +12 -3
- package/templates/base/tools/testin-nutin/watch-tests.js.hbs +45 -20
- package/templates/base/tools/utils/build-lock.js.hbs +30 -2
- package/templates/base/tools/utils/ensure-deps.js.hbs +72 -0
- package/templates/base/tools/utils/ensure-deps.test.js.hbs +17 -0
- package/templates/base/tools/utils/format.js.hbs +1 -1
- package/templates/base/tools/utils/index.js.hbs +2 -1
- package/templates/base/tools/utils/print.js.hbs +2 -2
- package/templates/base/tools/utils/resolve-port.js.hbs +30 -0
- package/templates/base/tools/utils/resolve-port.test.js.hbs +47 -0
- package/templates/base/tools/utils/run-command.js.hbs +30 -1
- package/templates/base/tools/utils/run-command.test.js.hbs +12 -1
- package/templates/base/tools/utils/run-script.js.hbs +2 -2
- package/templates/features/docker/tools/docker/Dockerfile.template.hbs +3 -0
- package/templates/features/docker/tools/docker/nginx.conf.template +6 -4
- package/templates/features/docker/tools/docker/scripts/docker-ports.js.hbs +1 -1
- package/templates/features/docker/tools/docker/scripts/docker-ports.test.js.hbs +2 -2
- package/templates/features/docker/tools/docker/scripts/locale-redirects.js.hbs +28 -0
- package/templates/features/docker/tools/docker/scripts/locale-redirects.test.js.hbs +34 -0
- package/templates/features/docker/tools/docker/scripts/markdown-sources-copy.js.hbs +25 -0
- package/templates/features/docker/tools/docker/scripts/markdown-sources-copy.test.js.hbs +34 -0
- package/templates/features/docker/tools/docker/scripts/render-docker-template.js.hbs +3 -1
- package/templates/features/docker/tools/docker/scripts/render-docker-template.test.js.hbs +12 -0
- package/templates/features/docker/tools/docker/scripts/validate-docker.js.hbs +21 -4
- package/templates/features/markdown/markdown-content/getting-started.md.hbs +28 -0
- package/templates/features/markdown/markdown-content/writing-pages.md.hbs +19 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-content/markdown-content.component.scss.hbs +75 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-content/markdown-content.component.test.js.hbs +40 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-content/markdown-content.component.ts.hbs +65 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-landing/markdown-landing.component.test.js.hbs +67 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-landing/markdown-landing.component.ts.hbs +87 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-nav/markdown-nav.component.scss.hbs +42 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-nav/markdown-nav.component.test.js.hbs +59 -0
- package/templates/features/markdown/src/app/markdown/components/markdown-nav/markdown-nav.component.ts.hbs +72 -0
- package/templates/features/markdown/src/app/markdown/locales/en.json.hbs +6 -0
- package/templates/features/markdown/src/app/markdown/markdown-guards.test.js.hbs +63 -0
- package/templates/features/markdown/src/app/markdown/markdown-guards.ts.hbs +31 -0
- package/templates/features/markdown/src/app/markdown/markdown-i18n.test.js.hbs +78 -0
- package/templates/features/markdown/src/app/markdown/markdown-i18n.ts.hbs +31 -0
- package/templates/features/markdown/src/app/markdown/markdown-manifest.test.js.hbs +98 -0
- package/templates/features/markdown/src/app/markdown/markdown-manifest.ts.hbs +157 -0
- package/templates/features/markdown/src/app/markdown/markdown-manifests.service.test.js.hbs +87 -0
- package/templates/features/markdown/src/app/markdown/markdown-manifests.service.ts.hbs +50 -0
- package/templates/features/markdown/src/app/markdown/markdown-routes.test.js.hbs +74 -0
- package/templates/features/markdown/src/app/markdown/markdown-routes.ts.hbs +26 -0
- package/templates/features/markdown/src/app/markdown/markdown-sources.test.js.hbs +22 -0
- package/templates/features/markdown/src/app/markdown/markdown-sources.ts.hbs +42 -0
- package/templates/features/markdown/src/app/markdown/view/markdown.view.html.hbs +4 -0
- package/templates/features/markdown/src/app/markdown/view/markdown.view.scss.hbs +19 -0
- package/templates/features/markdown/src/app/markdown/view/markdown.view.test.js.hbs +125 -0
- package/templates/features/markdown/src/app/markdown/view/markdown.view.ts.hbs +146 -0
- package/templates/features/markdown/tools/builder/core/markdown/generate-markdown-pages.js.hbs +71 -0
- package/templates/features/markdown/tools/builder/core/markdown/markdown-compiler.js.hbs +582 -0
- package/templates/features/markdown/tools/builder/core/markdown/markdown-compiler.test.js.hbs +390 -0
- package/templates/features/markdown/tools/builder/core/markdown/markdown-seo-routes.js.hbs +155 -0
- package/templates/features/markdown/tools/builder/core/markdown/markdown-seo-routes.test.js.hbs +112 -0
- /package/templates/base/tools/testin-nutin/core/{tests → globals}/clock.test.js.hbs +0 -0
|
@@ -20,7 +20,6 @@ export function addTest(test) {
|
|
|
20
20
|
|
|
21
21
|
export async function runQueuedTests() {
|
|
22
22
|
printStart();
|
|
23
|
-
const startTime = performance.now();
|
|
24
23
|
const testAmount = testQueue.length;
|
|
25
24
|
const results = [];
|
|
26
25
|
let previousSuiteKey = null;
|
|
@@ -70,10 +69,10 @@ export async function runQueuedTests() {
|
|
|
70
69
|
|
|
71
70
|
previousSuiteKey = suiteKey(test);
|
|
72
71
|
previousSuite = test.suiteName;
|
|
73
|
-
previousSuiteAfterAll = test.afterAll;
|
|
74
|
-
if (test.beforeAll) {
|
|
72
|
+
previousSuiteAfterAll = test.hooks?.afterAll;
|
|
73
|
+
if (test.hooks?.beforeAll) {
|
|
75
74
|
try {
|
|
76
|
-
await test.beforeAll();
|
|
75
|
+
await test.hooks.beforeAll();
|
|
77
76
|
} catch (err) {
|
|
78
77
|
failed++;
|
|
79
78
|
results.push({
|
|
@@ -99,7 +98,7 @@ export async function runQueuedTests() {
|
|
|
99
98
|
|
|
100
99
|
let testError = null;
|
|
101
100
|
try {
|
|
102
|
-
if (test.beforeEach) await test.beforeEach();
|
|
101
|
+
if (test.hooks?.beforeEach) await test.hooks.beforeEach();
|
|
103
102
|
await test.testFn();
|
|
104
103
|
} catch (err) {
|
|
105
104
|
testError = err;
|
|
@@ -107,7 +106,7 @@ export async function runQueuedTests() {
|
|
|
107
106
|
|
|
108
107
|
let afterEachError = null;
|
|
109
108
|
try {
|
|
110
|
-
if (test.afterEach) await test.afterEach();
|
|
109
|
+
if (test.hooks?.afterEach) await test.hooks.afterEach();
|
|
111
110
|
} catch (err) {
|
|
112
111
|
afterEachError = err;
|
|
113
112
|
}
|
|
@@ -145,8 +144,9 @@ export async function runQueuedTests() {
|
|
|
145
144
|
teardownJsdom();
|
|
146
145
|
}
|
|
147
146
|
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
// Since the process started (performance's time origin): Node startup, discovery and
|
|
148
|
+
// the test files' imports count too, not only running the queued tests.
|
|
149
|
+
elapsedTime = performance.now();
|
|
150
150
|
printResults(results);
|
|
151
151
|
printSummary(todo, passed, failed, elapsedTime);
|
|
152
152
|
|
|
@@ -1,45 +1,47 @@
|
|
|
1
1
|
import { createMockMethod } from './create-mock-method.js';
|
|
2
2
|
|
|
3
|
+
// Mirrors EventBus's public API (subscribe/once/emit/off): every method is a trackable
|
|
4
|
+
// mock whose default implementation really dispatches, so subscribed callbacks run.
|
|
3
5
|
export class MockEventBus {
|
|
4
6
|
constructor() {
|
|
5
7
|
this.handlers = {};
|
|
6
8
|
|
|
7
|
-
this.subscribe = createMockMethod();
|
|
8
|
-
this.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.off = (event, callback) => {
|
|
20
|
-
this.
|
|
21
|
-
|
|
22
|
-
this.handlers[event] = this.handlers[event].filter(cb => cb !== callback);
|
|
23
|
-
};
|
|
24
|
-
this.off.calls = [];
|
|
25
|
-
this.off.mockReset = () => { this.off.calls = []; };
|
|
26
|
-
|
|
27
|
-
this.on = createMockMethod((event, callback) => {
|
|
28
|
-
if (!this.handlers[event]) this.handlers[event] = [];
|
|
29
|
-
this.handlers[event].push(callback);
|
|
9
|
+
this.subscribe = createMockMethod((event, callback) => this._addHandler(event, callback, false));
|
|
10
|
+
this.once = createMockMethod((event, callback) => this._addHandler(event, callback, true));
|
|
11
|
+
|
|
12
|
+
this.emit = createMockMethod((event, data) => {
|
|
13
|
+
const entries = this.handlers[event];
|
|
14
|
+
if (!entries) return;
|
|
15
|
+
entries.slice().forEach((entry) => {
|
|
16
|
+
if (entry.once) this._removeHandler(event, entry.callback);
|
|
17
|
+
entry.callback(data);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
this.off = createMockMethod((event, callback) => {
|
|
22
|
+
if (callback) this._removeHandler(event, callback);
|
|
23
|
+
else delete this.handlers[event];
|
|
30
24
|
});
|
|
31
25
|
|
|
32
26
|
this.onDestroy = createMockMethod();
|
|
33
27
|
this.reset = this.reset.bind(this);
|
|
34
28
|
}
|
|
35
29
|
|
|
30
|
+
_addHandler(event, callback, once) {
|
|
31
|
+
(this.handlers[event] ??= []).push({ callback, once });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_removeHandler(event, callback) {
|
|
35
|
+
if (!this.handlers[event]) return;
|
|
36
|
+
this.handlers[event] = this.handlers[event].filter((entry) => entry.callback !== callback);
|
|
37
|
+
}
|
|
38
|
+
|
|
36
39
|
reset() {
|
|
37
40
|
this.subscribe.mockReset();
|
|
41
|
+
this.once.mockReset();
|
|
38
42
|
this.emit.mockReset();
|
|
39
43
|
this.off.mockReset();
|
|
40
|
-
this.on.mockReset();
|
|
41
44
|
this.onDestroy.mockReset();
|
|
42
45
|
this.handlers = {};
|
|
43
46
|
}
|
|
44
47
|
}
|
|
45
|
-
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { MockEventBus } from './mock-event-bus.js';
|
|
2
2
|
|
|
3
3
|
describe('MockEventBus', () => {
|
|
4
|
-
it('
|
|
4
|
+
it('subscribe() + emit() dispatches the event data to the subscribed callback', () => {
|
|
5
5
|
const bus = new MockEventBus();
|
|
6
6
|
let received;
|
|
7
|
-
bus.
|
|
7
|
+
bus.subscribe('greet', (data) => { received = data; });
|
|
8
8
|
|
|
9
9
|
bus.emit('greet', 'hello');
|
|
10
10
|
|
|
@@ -12,53 +12,61 @@ describe('MockEventBus', () => {
|
|
|
12
12
|
expect(bus.emit.calls).toEqual([['greet', 'hello']]);
|
|
13
13
|
});
|
|
14
14
|
|
|
15
|
-
it('
|
|
15
|
+
it('subscribe() is a trackable mock', () => {
|
|
16
16
|
const bus = new MockEventBus();
|
|
17
17
|
const handler = () => {};
|
|
18
|
-
bus.
|
|
18
|
+
bus.subscribe('greet', handler);
|
|
19
19
|
|
|
20
|
-
expect(bus.
|
|
21
|
-
expect(bus.on).toHaveBeenCalledWith('greet', handler);
|
|
20
|
+
expect(bus.subscribe).toHaveBeenCalledWith('greet', handler);
|
|
22
21
|
});
|
|
23
22
|
|
|
24
|
-
it('
|
|
23
|
+
it('once() callbacks run for the first emit only', () => {
|
|
25
24
|
const bus = new MockEventBus();
|
|
26
25
|
let callCount = 0;
|
|
27
|
-
|
|
28
|
-
bus.on('greet', handler);
|
|
29
|
-
bus.off('greet', handler);
|
|
26
|
+
bus.once('greet', () => { callCount++; });
|
|
30
27
|
|
|
31
|
-
bus.emit('greet'
|
|
28
|
+
bus.emit('greet');
|
|
29
|
+
bus.emit('greet');
|
|
32
30
|
|
|
33
|
-
expect(callCount).toBe(
|
|
31
|
+
expect(callCount).toBe(1);
|
|
34
32
|
});
|
|
35
33
|
|
|
36
|
-
it('
|
|
34
|
+
it('off(event, callback) removes that callback only', () => {
|
|
37
35
|
const bus = new MockEventBus();
|
|
38
|
-
let
|
|
39
|
-
|
|
36
|
+
let removed = 0;
|
|
37
|
+
let kept = 0;
|
|
38
|
+
const handler = () => { removed++; };
|
|
40
39
|
bus.subscribe('greet', handler);
|
|
40
|
+
bus.subscribe('greet', () => { kept++; });
|
|
41
|
+
bus.off('greet', handler);
|
|
41
42
|
|
|
42
43
|
bus.emit('greet', 'hello');
|
|
43
44
|
|
|
44
|
-
expect(
|
|
45
|
-
expect(
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
expect(removed).toBe(0);
|
|
46
|
+
expect(kept).toBe(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('off(event) removes every callback for that event', () => {
|
|
50
|
+
const bus = new MockEventBus();
|
|
51
|
+
let callCount = 0;
|
|
52
|
+
bus.subscribe('greet', () => { callCount++; });
|
|
53
|
+
bus.off('greet');
|
|
54
|
+
|
|
55
|
+
bus.emit('greet');
|
|
56
|
+
|
|
57
|
+
expect(callCount).toBe(0);
|
|
48
58
|
});
|
|
49
59
|
|
|
50
60
|
it('reset() clears handlers and call logs', () => {
|
|
51
61
|
const bus = new MockEventBus();
|
|
52
62
|
let callCount = 0;
|
|
53
|
-
bus.
|
|
63
|
+
bus.subscribe('greet', () => { callCount++; });
|
|
54
64
|
bus.emit('greet', 'x');
|
|
55
|
-
bus.subscribe('greet', () => {});
|
|
56
65
|
|
|
57
66
|
bus.reset();
|
|
58
67
|
|
|
59
68
|
expect(bus.emit.calls).toEqual([]);
|
|
60
69
|
expect(bus.subscribe.calls).toEqual([]);
|
|
61
|
-
expect(bus.on.calls).toEqual([]);
|
|
62
70
|
|
|
63
71
|
bus.emit('greet', 'y');
|
|
64
72
|
expect(callCount).toBe(1); // only the pre-reset emit reached the handler
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import { createMockMethod } from './create-mock-method.js';
|
|
2
2
|
|
|
3
|
+
const METHODS = ['get', 'post', 'put', 'patch', 'delete', 'addRequestInterceptor', 'addResponseInterceptor', 'onDestroy'];
|
|
4
|
+
|
|
5
|
+
// Mirrors HttpClient's public API; every method is a bare mock (configure responses
|
|
6
|
+
// with e.g. `client.get.mockReturnValue(Promise.resolve(data))`).
|
|
3
7
|
export class MockHttpClient {
|
|
4
8
|
constructor() {
|
|
5
|
-
|
|
6
|
-
this.onDestroy = createMockMethod();
|
|
7
|
-
this.reset = this.reset.bind(this);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
_defineHttpMethods() {
|
|
11
|
-
const methods = ['get', 'post', 'put', 'patch', 'delete'];
|
|
12
|
-
for (const method of methods) {
|
|
9
|
+
for (const method of METHODS) {
|
|
13
10
|
this[method] = createMockMethod();
|
|
14
11
|
}
|
|
12
|
+
this.reset = this.reset.bind(this);
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
reset() {
|
|
18
|
-
const
|
|
19
|
-
for (const method of methods) {
|
|
16
|
+
for (const method of METHODS) {
|
|
20
17
|
this[method].mockReset();
|
|
21
18
|
}
|
|
22
19
|
}
|
|
@@ -11,16 +11,28 @@ describe('MockHttpClient', () => {
|
|
|
11
11
|
expect(client.put.calls).toEqual([]);
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
+
it('exposes the interceptor registration methods as mocks', () => {
|
|
15
|
+
const client = new MockHttpClient();
|
|
16
|
+
const interceptor = () => {};
|
|
17
|
+
client.addRequestInterceptor(interceptor);
|
|
18
|
+
client.addResponseInterceptor(interceptor);
|
|
19
|
+
|
|
20
|
+
expect(client.addRequestInterceptor).toHaveBeenCalledWith(interceptor);
|
|
21
|
+
expect(client.addResponseInterceptor).toHaveBeenCalledWith(interceptor);
|
|
22
|
+
});
|
|
23
|
+
|
|
14
24
|
it('reset() clears calls and configured return values on every method', () => {
|
|
15
25
|
const client = new MockHttpClient();
|
|
16
26
|
client.get.mockReturnValue('cached');
|
|
17
27
|
client.get();
|
|
18
28
|
client.delete('/widgets/1');
|
|
29
|
+
client.addRequestInterceptor(() => {});
|
|
19
30
|
|
|
20
31
|
client.reset();
|
|
21
32
|
|
|
22
33
|
expect(client.get.calls).toEqual([]);
|
|
23
34
|
expect(client.delete.calls).toEqual([]);
|
|
35
|
+
expect(client.addRequestInterceptor.calls).toEqual([]);
|
|
24
36
|
expect(client.get()).toBe(undefined);
|
|
25
37
|
});
|
|
26
38
|
});
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createMockMethod } from './create-mock-method.js';
|
|
2
2
|
|
|
3
|
+
// Mirrors I18n's public API with in-memory translations (seed them with
|
|
4
|
+
// setTranslations()/setDefaultTranslations()); no fetch, no localStorage.
|
|
3
5
|
export class MockI18n {
|
|
4
6
|
constructor(defaultLang = 'en', supportedLangs = ['en']) {
|
|
5
7
|
this._DEFAULT_LANGUAGE = defaultLang;
|
|
@@ -7,39 +9,41 @@ export class MockI18n {
|
|
|
7
9
|
this._translations = {};
|
|
8
10
|
this._defaultTranslations = {};
|
|
9
11
|
this._currentLanguage = defaultLang;
|
|
12
|
+
this._languageListeners = [];
|
|
10
13
|
|
|
11
14
|
this.loadTranslations = createMockMethod(async (lang) => {
|
|
12
15
|
this._currentLanguage = lang;
|
|
13
16
|
});
|
|
14
17
|
|
|
15
|
-
this.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return Object.entries(params).reduce(
|
|
19
|
-
(acc, [k, v]) => acc.replace(`{${k}}`, v),
|
|
20
|
-
value
|
|
21
|
-
);
|
|
18
|
+
this.setCurrentLanguage = createMockMethod(async (lang) => {
|
|
19
|
+
await this.loadTranslations(lang);
|
|
20
|
+
this._languageListeners.forEach((callback) => callback({ lang }));
|
|
22
21
|
});
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
// Returns the unsubscribe function, like I18n.onLanguageChange.
|
|
24
|
+
this.onLanguageChange = createMockMethod((callback) => {
|
|
25
|
+
this._languageListeners.push(callback);
|
|
26
|
+
return () => {
|
|
27
|
+
this._languageListeners = this._languageListeners.filter((listener) => listener !== callback);
|
|
28
|
+
};
|
|
27
29
|
});
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.
|
|
31
|
+
// Same lookup as I18n.translate: nested dot keys, default-language fallback,
|
|
32
|
+
// then the given textContent, then the key itself.
|
|
33
|
+
this.translate = createMockMethod((key, textContent) => {
|
|
34
|
+
return this._lookup(key) || textContent || key;
|
|
33
35
|
});
|
|
34
36
|
|
|
35
|
-
this.
|
|
37
|
+
this.getTranslationObject = createMockMethod((key) => this._lookup(key) || null);
|
|
36
38
|
|
|
37
|
-
this.
|
|
38
|
-
this.
|
|
39
|
+
this.initTranslations = createMockMethod(async () => {
|
|
40
|
+
await this.loadTranslations(this._DEFAULT_LANGUAGE);
|
|
39
41
|
});
|
|
40
42
|
|
|
41
|
-
this.
|
|
42
|
-
|
|
43
|
+
this.resetTranslations = createMockMethod(() => {
|
|
44
|
+
this._translations = {};
|
|
45
|
+
this._defaultTranslations = {};
|
|
46
|
+
this._currentLanguage = this._DEFAULT_LANGUAGE;
|
|
43
47
|
});
|
|
44
48
|
|
|
45
49
|
this.onDestroy = createMockMethod(() => {
|
|
@@ -51,6 +55,26 @@ export class MockI18n {
|
|
|
51
55
|
return this._currentLanguage;
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
get defaultLanguage() {
|
|
59
|
+
return this._DEFAULT_LANGUAGE;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get languages() {
|
|
63
|
+
return this._LANGUAGES;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get localStorageKey() {
|
|
67
|
+
return 'nutin-fav-lang';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_lookup(key) {
|
|
71
|
+
const keys = key.split('.');
|
|
72
|
+
const read = (obj) => keys.reduce((acc, k) => acc?.[k], obj);
|
|
73
|
+
let value = read(this._translations);
|
|
74
|
+
if (!value && this._currentLanguage !== this._DEFAULT_LANGUAGE) value = read(this._defaultTranslations);
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
|
|
54
78
|
setTranslations(translations) {
|
|
55
79
|
this._translations = translations;
|
|
56
80
|
}
|
|
@@ -61,16 +85,17 @@ export class MockI18n {
|
|
|
61
85
|
|
|
62
86
|
reset() {
|
|
63
87
|
this.loadTranslations.mockReset();
|
|
88
|
+
this.setCurrentLanguage.mockReset();
|
|
89
|
+
this.onLanguageChange.mockReset();
|
|
64
90
|
this.translate.mockReset();
|
|
91
|
+
this.getTranslationObject.mockReset();
|
|
65
92
|
this.initTranslations.mockReset();
|
|
66
93
|
this.resetTranslations.mockReset();
|
|
67
|
-
this.getBrowserLanguage.mockReset();
|
|
68
|
-
this.loadDefaultTranslations.mockReset();
|
|
69
|
-
this.getNestedValue.mockReset();
|
|
70
94
|
this.onDestroy.mockReset();
|
|
71
95
|
|
|
72
96
|
this._translations = {};
|
|
73
97
|
this._defaultTranslations = {};
|
|
74
98
|
this._currentLanguage = this._DEFAULT_LANGUAGE;
|
|
99
|
+
this._languageListeners = [];
|
|
75
100
|
}
|
|
76
101
|
}
|
|
@@ -1,57 +1,78 @@
|
|
|
1
1
|
import { MockI18n } from './mock-i18n.js';
|
|
2
2
|
|
|
3
3
|
describe('MockI18n', () => {
|
|
4
|
-
it('exposes the constructor defaults via
|
|
4
|
+
it('exposes the constructor defaults via the language getters', () => {
|
|
5
5
|
const i18n = new MockI18n('fr', ['en', 'fr']);
|
|
6
|
+
|
|
6
7
|
expect(i18n.currentLanguage).toBe('fr');
|
|
8
|
+
expect(i18n.defaultLanguage).toBe('fr');
|
|
9
|
+
expect(i18n.languages).toEqual(['en', 'fr']);
|
|
7
10
|
});
|
|
8
11
|
|
|
9
|
-
it('translate
|
|
12
|
+
it('translate() falls back to textContent, then to the key itself', () => {
|
|
10
13
|
const i18n = new MockI18n();
|
|
11
14
|
|
|
12
|
-
|
|
15
|
+
expect(i18n.translate('some.key', 'Fallback text')).toBe('Fallback text');
|
|
13
16
|
expect(i18n.translate('some.key')).toBe('some.key');
|
|
14
|
-
expect(i18n.getBrowserLanguage()).toBe('en');
|
|
15
17
|
});
|
|
16
18
|
|
|
17
|
-
it('
|
|
18
|
-
const i18n = new MockI18n(
|
|
19
|
+
it('translate() resolves nested dot keys from setTranslations()', () => {
|
|
20
|
+
const i18n = new MockI18n();
|
|
21
|
+
i18n.setTranslations({ home: { title: 'Home' } });
|
|
19
22
|
|
|
23
|
+
expect(i18n.translate('home.title')).toBe('Home');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('translate() falls back to the default-language translations off the default language', async () => {
|
|
27
|
+
const i18n = new MockI18n('en', ['en', 'fr']);
|
|
28
|
+
i18n.setDefaultTranslations({ greeting: 'Hello' });
|
|
20
29
|
await i18n.loadTranslations('fr');
|
|
21
|
-
|
|
30
|
+
|
|
31
|
+
expect(i18n.translate('greeting')).toBe('Hello');
|
|
22
32
|
});
|
|
23
33
|
|
|
24
|
-
it('
|
|
34
|
+
it('getTranslationObject() returns the nested value, or null', () => {
|
|
25
35
|
const i18n = new MockI18n();
|
|
26
|
-
i18n.
|
|
36
|
+
i18n.setTranslations({ nav: { home: 'Home', about: 'About' } });
|
|
27
37
|
|
|
28
|
-
expect(i18n.
|
|
38
|
+
expect(i18n.getTranslationObject('nav')).toEqual({ home: 'Home', about: 'About' });
|
|
39
|
+
expect(i18n.getTranslationObject('missing')).toBe(null);
|
|
29
40
|
});
|
|
30
41
|
|
|
31
|
-
it('
|
|
32
|
-
const i18n = new MockI18n();
|
|
33
|
-
|
|
34
|
-
i18n.
|
|
35
|
-
const value = i18n._translations[key] || key;
|
|
36
|
-
if (!params) return value;
|
|
37
|
-
return Object.entries(params).reduce((acc, [k, v]) => acc.replace(`{${k}}`, v), value);
|
|
38
|
-
});
|
|
42
|
+
it('setCurrentLanguage() updates currentLanguage and notifies onLanguageChange() callbacks', async () => {
|
|
43
|
+
const i18n = new MockI18n('en', ['en', 'fr']);
|
|
44
|
+
let payload;
|
|
45
|
+
i18n.onLanguageChange((data) => { payload = data; });
|
|
39
46
|
|
|
40
|
-
|
|
47
|
+
await i18n.setCurrentLanguage('fr');
|
|
48
|
+
|
|
49
|
+
expect(i18n.currentLanguage).toBe('fr');
|
|
50
|
+
expect(payload).toEqual({ lang: 'fr' });
|
|
51
|
+
expect(i18n.setCurrentLanguage).toHaveBeenCalledWith('fr');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('onLanguageChange() returns a function that stops further notifications', async () => {
|
|
55
|
+
const i18n = new MockI18n('en', ['en', 'fr']);
|
|
56
|
+
let calls = 0;
|
|
57
|
+
const unsubscribe = i18n.onLanguageChange(() => { calls++; });
|
|
58
|
+
unsubscribe();
|
|
59
|
+
|
|
60
|
+
await i18n.setCurrentLanguage('fr');
|
|
61
|
+
|
|
62
|
+
expect(calls).toBe(0);
|
|
41
63
|
});
|
|
42
64
|
|
|
43
|
-
it('
|
|
65
|
+
it('translate is still trackable as a mock alongside its default implementation', () => {
|
|
44
66
|
const i18n = new MockI18n();
|
|
45
|
-
i18n.
|
|
46
|
-
i18n.setDefaultTranslations({ b: '2' });
|
|
67
|
+
i18n.translate('some.key');
|
|
47
68
|
|
|
48
|
-
expect(i18n.
|
|
49
|
-
expect(i18n._defaultTranslations).toEqual({ b: '2' });
|
|
69
|
+
expect(i18n.translate).toHaveBeenCalledWith('some.key');
|
|
50
70
|
});
|
|
51
71
|
|
|
52
|
-
it('reset() restores the constructor default language and clears translations', () => {
|
|
53
|
-
const i18n = new MockI18n('en');
|
|
72
|
+
it('reset() restores the constructor default language and clears translations', async () => {
|
|
73
|
+
const i18n = new MockI18n('en', ['en', 'fr']);
|
|
54
74
|
i18n.setTranslations({ a: '1' });
|
|
75
|
+
await i18n.setCurrentLanguage('fr');
|
|
55
76
|
|
|
56
77
|
i18n.reset();
|
|
57
78
|
|
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import { createMockMethod } from './create-mock-method.js';
|
|
2
2
|
|
|
3
|
+
// Mirrors Router's public API. Route params are seeded with setParams() and read back
|
|
4
|
+
// through the real getCurrentParams()/getParam() shapes.
|
|
3
5
|
export class MockRouter {
|
|
4
6
|
constructor(routes = {}) {
|
|
5
7
|
this.routes = routes;
|
|
6
|
-
this.
|
|
8
|
+
this._currentParams = {};
|
|
7
9
|
|
|
8
|
-
this.navigate = createMockMethod();
|
|
9
|
-
this.
|
|
10
|
-
this.
|
|
11
|
-
this.
|
|
12
|
-
this.
|
|
10
|
+
this.navigate = createMockMethod(async () => {});
|
|
11
|
+
this.reload = createMockMethod(async () => {});
|
|
12
|
+
this.getCurrentParams = createMockMethod(() => ({ ...this._currentParams }));
|
|
13
|
+
this.getParam = createMockMethod((key) => this._currentParams[key]);
|
|
14
|
+
this.removeEventListeners = createMockMethod();
|
|
15
|
+
this.onDestroy = createMockMethod();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setParams(params) {
|
|
19
|
+
this._currentParams = { ...params };
|
|
13
20
|
}
|
|
14
21
|
|
|
15
22
|
reset() {
|
|
16
23
|
this.navigate.mockReset();
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
24
|
+
this.reload.mockReset();
|
|
25
|
+
this.getCurrentParams.mockReset();
|
|
26
|
+
this.getParam.mockReset();
|
|
27
|
+
this.removeEventListeners.mockReset();
|
|
28
|
+
this.onDestroy.mockReset();
|
|
29
|
+
this._currentParams = {};
|
|
22
30
|
}
|
|
23
31
|
}
|
|
@@ -8,22 +8,39 @@ describe('MockRouter', () => {
|
|
|
8
8
|
expect(router.routes).toBe(routes);
|
|
9
9
|
});
|
|
10
10
|
|
|
11
|
-
it('navigate/
|
|
11
|
+
it('navigate/reload are independent trackable mocks', async () => {
|
|
12
12
|
const router = new MockRouter();
|
|
13
|
-
router.navigate('/about');
|
|
13
|
+
await router.navigate('/about');
|
|
14
14
|
|
|
15
15
|
expect(router.navigate.calls).toEqual([['/about']]);
|
|
16
|
-
expect(router.
|
|
16
|
+
expect(router.reload.calls).toEqual([]);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('
|
|
19
|
+
it('getCurrentParams/getParam read the params seeded with setParams()', () => {
|
|
20
20
|
const router = new MockRouter();
|
|
21
|
-
router.
|
|
22
|
-
|
|
21
|
+
router.setParams({ id: '42' });
|
|
22
|
+
|
|
23
|
+
expect(router.getCurrentParams()).toEqual({ id: '42' });
|
|
24
|
+
expect(router.getParam('id')).toBe('42');
|
|
25
|
+
expect(router.getParam('missing')).toBe(undefined);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('getCurrentParams returns a copy', () => {
|
|
29
|
+
const router = new MockRouter();
|
|
30
|
+
router.setParams({ id: '42' });
|
|
31
|
+
router.getCurrentParams().id = 'changed';
|
|
32
|
+
|
|
33
|
+
expect(router.getParam('id')).toBe('42');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('reset() clears every mock method and the seeded params', async () => {
|
|
37
|
+
const router = new MockRouter();
|
|
38
|
+
await router.navigate('/about');
|
|
39
|
+
router.setParams({ id: '42' });
|
|
23
40
|
|
|
24
41
|
router.reset();
|
|
25
42
|
|
|
26
43
|
expect(router.navigate.calls).toEqual([]);
|
|
27
|
-
expect(router.
|
|
44
|
+
expect(router.getCurrentParams()).toEqual({});
|
|
28
45
|
});
|
|
29
46
|
});
|
|
@@ -12,7 +12,9 @@ const verboseEnabled = args.includes('--verbose');
|
|
|
12
12
|
const fileFilters = args.filter(arg => arg !== '--coverage' && arg !== '--verbose');
|
|
13
13
|
|
|
14
14
|
// Tests import and run the compiled build output (dist/src/)
|
|
15
|
+
{{#unless (eq lang "js")}}
|
|
15
16
|
// and has no sourcemap back to the .ts sources
|
|
17
|
+
{{/unless}}
|
|
16
18
|
const origins = [];
|
|
17
19
|
const coverageDirs = [];
|
|
18
20
|
|
|
@@ -41,10 +43,8 @@ if (fileFilters.length) {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
async function loadTestFile(file) {
|
|
44
|
-
setupJsdom();
|
|
45
46
|
setCurrentTestFile(file);
|
|
46
47
|
await import(file);
|
|
47
|
-
teardownJsdom();
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
async function runCoverage(testResults) {
|
|
@@ -77,18 +77,27 @@ async function runTests() {
|
|
|
77
77
|
|
|
78
78
|
if (coverageEnabled) await startCoverage();
|
|
79
79
|
|
|
80
|
+
// One DOM for importing every file (module-level code may use it); each suite
|
|
81
|
+
// then runs in a fresh one (see runQueuedTests).
|
|
82
|
+
let loadFailures = 0;
|
|
83
|
+
setupJsdom();
|
|
80
84
|
for (const file of testFiles) {
|
|
81
85
|
try {
|
|
82
86
|
await loadTestFile(file);
|
|
83
87
|
} catch (error) {
|
|
88
|
+
loadFailures++;
|
|
84
89
|
print.boldError(`✗ ${file} failed to load:`);
|
|
85
90
|
print.grayError(error.stack);
|
|
86
91
|
}
|
|
87
92
|
}
|
|
93
|
+
teardownJsdom();
|
|
88
94
|
|
|
89
95
|
const testResults = await runQueuedTests();
|
|
90
96
|
|
|
91
|
-
if (
|
|
97
|
+
if (loadFailures > 0) {
|
|
98
|
+
print.boldError(`✗ ${loadFailures} test file(s) failed to load — see errors above.\n`);
|
|
99
|
+
}
|
|
100
|
+
if (testResults.failed > 0 || loadFailures > 0) process.exitCode = 1;
|
|
92
101
|
|
|
93
102
|
if (coverageEnabled) await runCoverage(testResults);
|
|
94
103
|
}
|