Browse Source

Merge pull request #24530 from abpframework/fix/#24495-migrating-ui-tests-to-vitest

Angular - Migrating UI Tests to Vitest
pull/24704/head
erdem 2 weeks ago
committed by GitHub
parent
commit
3b8310b478
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 8
      .claude/settings.local.json
  2. 2
      npm/ng-packs/.gitignore
  3. 6
      npm/ng-packs/apps/dev-app/project.json
  4. 5
      npm/ng-packs/jest.config.ts
  5. 4
      npm/ng-packs/jest.preset.js
  6. 4
      npm/ng-packs/nx.json
  7. 16
      npm/ng-packs/package.json
  8. 2
      npm/ng-packs/packages/account-core/.eslintrc.json
  9. 4
      npm/ng-packs/packages/account-core/jest.config.ts
  10. 14
      npm/ng-packs/packages/account-core/project.json
  11. 19
      npm/ng-packs/packages/account-core/tsconfig.lib.json
  12. 22
      npm/ng-packs/packages/account-core/tsconfig.spec.json
  13. 21
      npm/ng-packs/packages/account-core/vitest.config.mts
  14. 2
      npm/ng-packs/packages/account/.eslintrc.json
  15. 4
      npm/ng-packs/packages/account/jest.config.ts
  16. 14
      npm/ng-packs/packages/account/project.json
  17. 19
      npm/ng-packs/packages/account/tsconfig.lib.json
  18. 22
      npm/ng-packs/packages/account/tsconfig.spec.json
  19. 21
      npm/ng-packs/packages/account/vitest.config.mts
  20. 2
      npm/ng-packs/packages/components/.eslintrc.json
  21. 4
      npm/ng-packs/packages/components/jest.config.ts
  22. 14
      npm/ng-packs/packages/components/project.json
  23. 14
      npm/ng-packs/packages/components/tsconfig.lib.json
  24. 22
      npm/ng-packs/packages/components/tsconfig.spec.json
  25. 21
      npm/ng-packs/packages/components/vitest.config.mts
  26. 2
      npm/ng-packs/packages/core/.eslintrc.json
  27. 23
      npm/ng-packs/packages/core/jest.config.ts
  28. 14
      npm/ng-packs/packages/core/project.json
  29. 3
      npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts
  30. 36
      npm/ng-packs/packages/core/src/lib/directives/for.directive.ts
  31. 26
      npm/ng-packs/packages/core/src/lib/directives/permission.directive.ts
  32. 3
      npm/ng-packs/packages/core/src/lib/services/list.service.ts
  33. 2
      npm/ng-packs/packages/core/src/lib/services/router-events.service.ts
  34. 6
      npm/ng-packs/packages/core/src/lib/tests/autofocus.directive.spec.ts
  35. 68
      npm/ng-packs/packages/core/src/lib/tests/capsLock.directive.spec.ts
  36. 44
      npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts
  37. 6
      npm/ng-packs/packages/core/src/lib/tests/container.strategy.spec.ts
  38. 5
      npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts
  39. 52
      npm/ng-packs/packages/core/src/lib/tests/content.strategy.spec.ts
  40. 2
      npm/ng-packs/packages/core/src/lib/tests/context.strategy.spec.ts
  41. 26
      npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts
  42. 14
      npm/ng-packs/packages/core/src/lib/tests/debounce.directive.spec.ts
  43. 19
      npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts
  44. 27
      npm/ng-packs/packages/core/src/lib/tests/dom.strategy.spec.ts
  45. 21
      npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts
  46. 8
      npm/ng-packs/packages/core/src/lib/tests/environment-utils.spec.ts
  47. 25
      npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts
  48. 35
      npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts
  49. 21
      npm/ng-packs/packages/core/src/lib/tests/form-submit.directive.spec.ts
  50. 13
      npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts
  51. 16
      npm/ng-packs/packages/core/src/lib/tests/internal-store.spec.ts
  52. 209
      npm/ng-packs/packages/core/src/lib/tests/internet-connection.service.spec.ts
  53. 106
      npm/ng-packs/packages/core/src/lib/tests/lazy-load-utils.spec.ts
  54. 10
      npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts
  55. 117
      npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts
  56. 40
      npm/ng-packs/packages/core/src/lib/tests/loading.strategy.spec.ts
  57. 12
      npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts
  58. 2
      npm/ng-packs/packages/core/src/lib/tests/locale.provider.spec.ts
  59. 4
      npm/ng-packs/packages/core/src/lib/tests/localization.pipe.spec.ts
  60. 22
      npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts
  61. 25
      npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts
  62. 2
      npm/ng-packs/packages/core/src/lib/tests/ng-model.component.spec.ts
  63. 41
      npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts
  64. 45
      npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
  65. 25
      npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts
  66. 2
      npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts
  67. 10
      npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts
  68. 20
      npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts
  69. 4
      npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts
  70. 2
      npm/ng-packs/packages/core/src/lib/tests/router-events.service.spec.ts
  71. 2
      npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts
  72. 4
      npm/ng-packs/packages/core/src/lib/tests/routes.handler.spec.ts
  73. 30
      npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts
  74. 4
      npm/ng-packs/packages/core/src/lib/tests/safe-html.pipe.spec.ts
  75. 118
      npm/ng-packs/packages/core/src/lib/tests/show-password-directive.spec.ts
  76. 2
      npm/ng-packs/packages/core/src/lib/tests/sort.pipe.spec.ts
  77. 9
      npm/ng-packs/packages/core/src/lib/tests/stop-propagation.directive.spec.ts
  78. 6
      npm/ng-packs/packages/core/src/lib/tests/subscription.service.spec.ts
  79. 10
      npm/ng-packs/packages/core/src/test-setup.ts
  80. 19
      npm/ng-packs/packages/core/tsconfig.lib.json
  81. 22
      npm/ng-packs/packages/core/tsconfig.spec.json
  82. 22
      npm/ng-packs/packages/core/vitest.config.mts
  83. 2
      npm/ng-packs/packages/feature-management/.eslintrc.json
  84. 4
      npm/ng-packs/packages/feature-management/jest.config.ts
  85. 14
      npm/ng-packs/packages/feature-management/project.json
  86. 19
      npm/ng-packs/packages/feature-management/tsconfig.lib.json
  87. 22
      npm/ng-packs/packages/feature-management/tsconfig.spec.json
  88. 21
      npm/ng-packs/packages/feature-management/vitest.config.mts
  89. 2
      npm/ng-packs/packages/generators/.eslintrc.json
  90. 4
      npm/ng-packs/packages/generators/jest.config.ts
  91. 6
      npm/ng-packs/packages/generators/project.json
  92. 6
      npm/ng-packs/packages/generators/src/generators/change-theme/generator.spec.ts
  93. 16
      npm/ng-packs/packages/generators/tsconfig.lib.json
  94. 19
      npm/ng-packs/packages/generators/tsconfig.spec.json
  95. 21
      npm/ng-packs/packages/generators/vitest.config.mts
  96. 2
      npm/ng-packs/packages/identity/.eslintrc.json
  97. 4
      npm/ng-packs/packages/identity/jest.config.ts
  98. 14
      npm/ng-packs/packages/identity/project.json
  99. 19
      npm/ng-packs/packages/identity/tsconfig.lib.json
  100. 22
      npm/ng-packs/packages/identity/tsconfig.spec.json

8
.claude/settings.local.json

@ -0,0 +1,8 @@
{
"permissions": {
"allow": [
"Bash(yarn nx g:*)",
"Bash(npx vitest:*)"
]
}
}

2
npm/ng-packs/.gitignore

@ -58,3 +58,5 @@ Thumbs.db
.angular
.nx/
vitest.config.*.timestamp*

6
npm/ng-packs/apps/dev-app/project.json

@ -175,10 +175,12 @@
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "@nx/jest:jest",
"executor": "@nx/vitest:test",
"outputs": ["{workspaceRoot}/coverage/apps/dev-app"],
"options": {
"jestConfig": "apps/dev-app/jest.config.ts"
"passWithNoTests": true,
"reportsDirectory": "../../coverage/apps/dev-app",
"silent": false
}
},
"serve-static": {

5
npm/ng-packs/jest.config.ts

@ -1,5 +1,8 @@
import { getJestProjectsAsync } from '@nx/jest';
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default async () => ({
projects: await getJestProjectsAsync(),
});

4
npm/ng-packs/jest.preset.js

@ -1,3 +1,7 @@
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
const nxPreset = require('@nx/jest/preset').default;
module.exports = {

4
npm/ng-packs/nx.json

@ -118,6 +118,10 @@
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
},
"@nx/vitest:test": {
"cache": true,
"inputs": ["default", "^production"]
}
},
"namedInputs": {

16
npm/ng-packs/package.json

@ -10,6 +10,8 @@
"build:all": "nx run-many --target=build --all --exclude=dev-app,schematics --prod && npm run build:schematics",
"test": "ng test --detect-open-handles=true --run-in-band=true --watch-all=true",
"test:all": "nx run-many --target=test --all",
"test:vitest": "vitest",
"test:vitest:project": "sh -c 'vitest --project \"${1:-core}\"' _",
"lint-staged": "lint-staged",
"lint": "nx workspace-lint && ng lint",
"lint:all": "nx run-many --target=lint --all",
@ -80,23 +82,26 @@
"@nx/eslint": "~22.2.0",
"@nx/eslint-plugin": "~22.2.0",
"@nx/jest": "~22.2.0",
"@nx/js": "~22.2.0",
"@nx/js": "22.2.7",
"@nx/plugin": "~22.2.0",
"@nx/vite": "22.2.7",
"@nx/vitest": "22.2.7",
"@nx/web": "~22.2.0",
"@nx/workspace": "~22.2.0",
"@popperjs/core": "~2.11.0",
"@schematics/angular": "~21.0.0",
"@swc-node/register": "1.9.2",
"@swc/cli": "0.6.0",
"@swc/core": "~1.5.0",
"@swc/helpers": "~0.5.0",
"@swc/core": "~1.5.7",
"@swc/helpers": "~0.5.11",
"@swimlane/ngx-datatable": "~22.0.0",
"@types/express": "~5.0.0",
"@types/jest": "29.5.14",
"@types/node": "~20.11.0",
"@types/node": "20.19.9",
"@typescript-eslint/eslint-plugin": "7.16.0",
"@typescript-eslint/parser": "7.16.0",
"@typescript-eslint/utils": "^7.16.0",
"@vitest/coverage-v8": "^4.0.0",
"angular-oauth2-oidc": "~20.0.0",
"autoprefixer": "^10.4.21",
"bootstrap": "~5.0.0",
@ -114,6 +119,7 @@
"jest-canvas-mock": "^2.0.0",
"jest-environment-jsdom": "^29.0.0",
"jest-preset-angular": "14.6.0",
"jsdom": "~22.1.0",
"jsonc-eslint-parser": "^2.0.0",
"jsonc-parser": "^2.0.0",
"just-clone": "^6.0.0",
@ -137,6 +143,8 @@
"tslib": "^2.3.0",
"tslint": "~6.1.0",
"typescript": "~5.9.0",
"vite": "^7.0.0",
"vitest": "^4.0.0",
"zone.js": "~0.15.0"
},
"lint-staged": {

2
npm/ng-packs/packages/account-core/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts"],

4
npm/ng-packs/packages/account-core/jest.config.ts

@ -1,4 +1,8 @@
/* eslint-disable */
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default {
displayName: 'account-core',
preset: '../../jest.preset.js',

14
npm/ng-packs/packages/account-core/project.json

@ -23,16 +23,16 @@
},
"defaultConfiguration": "production"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/account-core"],
"options": {
"jestConfig": "packages/account-core/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../coverage/packages/account-core"
}
}
}
}

19
npm/ng-packs/packages/account-core/tsconfig.lib.json

@ -10,6 +10,23 @@
"lib": ["dom", "es2020"],
"useDefineForClassFields": false
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"],
"exclude": [
"src/test-setup.ts",
"**/*.spec.ts",
"jest.config.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/test-setup.ts"
],
"include": ["**/*.ts"]
}

22
npm/ng-packs/packages/account-core/tsconfig.spec.json

@ -2,10 +2,22 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

21
npm/ng-packs/packages/account-core/vitest.config.mts

@ -0,0 +1,21 @@
import { defineConfig } from 'vitest/config';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/account-core',
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
test: {
name: 'account-core',
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/packages/account-core',
provider: 'v8' as const,
},
},
}));

2
npm/ng-packs/packages/account/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts"],

4
npm/ng-packs/packages/account/jest.config.ts

@ -1,4 +1,8 @@
/* eslint-disable */
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default {
displayName: 'account',
preset: '../../jest.preset.js',

14
npm/ng-packs/packages/account/project.json

@ -23,16 +23,16 @@
},
"defaultConfiguration": "production"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/account"],
"options": {
"jestConfig": "packages/account/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../coverage/packages/account"
}
}
}
}

19
npm/ng-packs/packages/account/tsconfig.lib.json

@ -10,6 +10,23 @@
"lib": ["dom", "es2020"],
"useDefineForClassFields": false
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"],
"exclude": [
"src/test-setup.ts",
"**/*.spec.ts",
"jest.config.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/test-setup.ts"
],
"include": ["**/*.ts"]
}

22
npm/ng-packs/packages/account/tsconfig.spec.json

@ -2,10 +2,22 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

21
npm/ng-packs/packages/account/vitest.config.mts

@ -0,0 +1,21 @@
import { defineConfig } from 'vitest/config';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/account',
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
test: {
name: 'account',
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/packages/account',
provider: 'v8' as const,
},
},
}));

2
npm/ng-packs/packages/components/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts"],

4
npm/ng-packs/packages/components/jest.config.ts

@ -1,4 +1,8 @@
/* eslint-disable */
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default {
displayName: 'components',
preset: '../../jest.preset.js',

14
npm/ng-packs/packages/components/project.json

@ -23,16 +23,16 @@
},
"defaultConfiguration": "production"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/components"],
"options": {
"jestConfig": "packages/components/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../coverage/packages/components"
}
}
}
}

14
npm/ng-packs/packages/components/tsconfig.lib.json

@ -13,7 +13,19 @@
"exclude": [
"src/test-setup.ts",
"src/**/*.spec.ts",
"jest.config.ts"
"jest.config.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/test-setup.ts"
],
"include": ["src/**/*.ts"]
}

22
npm/ng-packs/packages/components/tsconfig.spec.json

@ -2,10 +2,22 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

21
npm/ng-packs/packages/components/vitest.config.mts

@ -0,0 +1,21 @@
import { defineConfig } from 'vitest/config';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/components',
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
test: {
name: 'components',
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/packages/components',
provider: 'v8' as const,
},
},
}));

2
npm/ng-packs/packages/core/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts"],

23
npm/ng-packs/packages/core/jest.config.ts

@ -1,23 +0,0 @@
/* eslint-disable */
export default {
displayName: 'core',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {},
coverageDirectory: '../../coverage/packages/core',
transform: {
'^.+.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: ['node_modules/(?!.*.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};

14
npm/ng-packs/packages/core/project.json

@ -22,16 +22,16 @@
},
"defaultConfiguration": "production"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/core"],
"options": {
"jestConfig": "packages/core/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../coverage/packages/core"
}
}
}
}

3
npm/ng-packs/packages/core/src/lib/components/dynamic-layout.component.ts

@ -3,9 +3,6 @@ import {
inject,
input,
isDevMode,
OnInit,
Optional,
SkipSelf,
Type,
} from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';

36
npm/ng-packs/packages/core/src/lib/directives/for.directive.ts

@ -1,16 +1,16 @@
import {
Directive,
EmbeddedViewRef,
Input,
IterableChangeRecord,
IterableChanges,
IterableDiffer,
IterableDiffers,
OnChanges,
TemplateRef,
TrackByFunction,
ViewContainerRef,
inject
import {
Directive,
EmbeddedViewRef,
Input,
IterableChangeRecord,
IterableChanges,
IterableDiffer,
IterableDiffers,
OnChanges,
TemplateRef,
TrackByFunction,
ViewContainerRef,
inject,
} from '@angular/core';
import clone from 'just-clone';
import compare from 'just-compare';
@ -67,6 +67,7 @@ export class ForDirective implements OnChanges {
emptyRef?: TemplateRef<any>;
private differ!: IterableDiffer<any> | null;
private lastItemsRef: any[] | null = null;
private isShowEmptyRef!: boolean;
@ -136,6 +137,7 @@ export class ForDirective implements OnChanges {
this.vcRef.createEmbeddedView(this.emptyRef).rootNodes;
this.isShowEmptyRef = true;
this.differ = null;
this.lastItemsRef = null;
return;
}
@ -169,6 +171,14 @@ export class ForDirective implements OnChanges {
}
ngOnChanges() {
if (!this.items) return;
// Recreate differ if items array reference changed
if (this.lastItemsRef !== this.items) {
this.differ = null;
this.lastItemsRef = this.items;
}
let items = clone(this.items) as any[];
if (!Array.isArray(items)) return;

26
npm/ng-packs/packages/core/src/lib/directives/permission.directive.ts

@ -1,13 +1,13 @@
import {
AfterViewInit,
ChangeDetectorRef,
Directive,
Input,
OnChanges,
OnDestroy,
TemplateRef,
ViewContainerRef,
inject
import {
AfterViewInit,
ChangeDetectorRef,
Directive,
Input,
OnChanges,
OnDestroy,
TemplateRef,
ViewContainerRef,
inject,
} from '@angular/core';
import { ReplaySubject, Subscription } from 'rxjs';
import { distinctUntilChanged, take } from 'rxjs/operators';
@ -19,7 +19,7 @@ import { QueueManager } from '../utils/queue';
selector: '[abpPermission]',
})
export class PermissionDirective implements OnDestroy, OnChanges, AfterViewInit {
private templateRef = inject<TemplateRef<any>>(TemplateRef, { optional: true })!;
private templateRef = inject<TemplateRef<any>>(TemplateRef, { optional: true });
private vcRef = inject(ViewContainerRef);
private permissionService = inject(PermissionService);
private cdRef = inject(ChangeDetectorRef);
@ -45,7 +45,9 @@ export class PermissionDirective implements OnDestroy, OnChanges, AfterViewInit
.pipe(distinctUntilChanged())
.subscribe(isGranted => {
this.vcRef.clear();
if (isGranted) this.vcRef.createEmbeddedView(this.templateRef);
if (isGranted && this.templateRef) {
this.vcRef.createEmbeddedView(this.templateRef);
}
if (this.runChangeDetection) {
if (!this.rendered) {
this.cdrSubject.next();

3
npm/ng-packs/packages/core/src/lib/services/list.service.ts

@ -2,6 +2,7 @@ import { Injectable, Injector, OnDestroy, inject } from '@angular/core';
import {
EMPTY,
BehaviorSubject,
defer,
MonoTypeOperatorFunction,
Observable,
ReplaySubject,
@ -134,7 +135,7 @@ export class ListService<QueryParamsType = ABP.PageQueryParams | any> implements
tap(() => this._isLoading$.next(true)),
tap(() => this._requestStatus.next('loading')),
switchMap(query =>
streamCreatorCallback(query).pipe(
defer(() => streamCreatorCallback(query)).pipe(
catchError(() => {
this._requestStatus.next('error');
return EMPTY;

2
npm/ng-packs/packages/core/src/lib/services/router-events.service.ts

@ -34,7 +34,7 @@ export class RouterEvents {
protected listenToNavigation(): void {
const routerEvent$ = this.router.events.pipe(
filter(e => e instanceof NavigationEvent.End && !e.url.includes('error'))
filter(e => e instanceof NavigationEvent.End && e.url != null && !e.url.includes('error'))
) as Observable<NavigationEnd>;
routerEvent$.subscribe(event => {

6
npm/ng-packs/packages/core/src/lib/tests/autofocus.directive.spec.ts

@ -1,4 +1,4 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { AutofocusDirective } from '../directives/autofocus.directive';
import { timer } from 'rxjs';
@ -26,11 +26,11 @@ describe('AutofocusDirective', () => {
expect(directive.delay).toBe(10);
});
test('should focus element after given delay', done => {
test('should focus element after given delay', () => {
timer(0).subscribe(() => expect('input').not.toBeFocused());
timer(11).subscribe(() => {
expect('input').toBeFocused();
done();
expect.hasAssertions();
});
});
});

68
npm/ng-packs/packages/core/src/lib/tests/capsLock.directive.spec.ts

@ -1,26 +1,23 @@
import { Component, DebugElement } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { TrackCapsLockDirective } from '../directives';
import { By } from '@angular/platform-browser';
import { Component, DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { TrackCapsLockDirective } from '../directives';
@Component({
standalone:true,
template: `
<input (abpCapsLock)="capsLock = $event" />
`,
imports:[TrackCapsLockDirective]
template: ` <input (abpCapsLock)="capsLock = $event" /> `,
imports: [TrackCapsLockDirective],
})
class TestComponent {
capsLock = false
capsLock = false;
}
describe('TrackCapsLockDirective',()=>{
let fixture: ComponentFixture<TestComponent>;;
let des : DebugElement[];
describe('TrackCapsLockDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let des: DebugElement[];
beforeEach(()=>{
beforeEach(() => {
fixture = TestBed.configureTestingModule({
imports: [ TestComponent ]
imports: [TestComponent],
}).createComponent(TestComponent);
fixture.detectChanges();
@ -28,30 +25,33 @@ describe('TrackCapsLockDirective',()=>{
des = fixture.debugElement.queryAll(By.directive(TrackCapsLockDirective));
});
test.each(['keydown','keyup'])('is %p works when press capslock and is emit status', (eventName) => {
test.each(['keydown', 'keyup'])(
'is %p works when press capslock and is emit status',
eventName => {
const event = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: true
modifierCapsLock: true,
});
window.dispatchEvent(event);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true)
});
expect(fixture.componentInstance.capsLock).toBe(true);
},
);
test.each(['keydown','keyup'])('is %p detect the change capslock is emit status', (eventName) => {
const trueEvent = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: true
});
window.dispatchEvent(trueEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true)
const falseEvent = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: false
});
window.dispatchEvent(falseEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(false)
test.each(['keydown', 'keyup'])('is %p detect the change capslock is emit status', eventName => {
const trueEvent = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: true,
});
window.dispatchEvent(trueEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(true);
const falseEvent = new KeyboardEvent(eventName, {
key: 'CapsLock',
modifierCapsLock: false,
});
});
window.dispatchEvent(falseEvent);
fixture.detectChanges();
expect(fixture.componentInstance.capsLock).toBe(false);
});
});

44
npm/ng-packs/packages/core/src/lib/tests/config-state.service.spec.ts

@ -1,6 +1,6 @@
import { provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { of } from 'rxjs';
import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
import {
@ -132,7 +132,7 @@ describe('ConfigStateService', () => {
},
{
provide: AbpApplicationLocalizationService,
useValue: { get: () => APPLICATION_LOCALIZATION_DATA },
useValue: { get: () => of(APPLICATION_LOCALIZATION_DATA) },
},
IncludeLocalizationResourcesProvider,
],
@ -142,84 +142,84 @@ describe('ConfigStateService', () => {
spectator = createService();
configState = spectator.service;
jest.spyOn(configState, 'getAll').mockReturnValue(CONFIG_STATE_DATA);
jest.spyOn(configState, 'getAll$').mockReturnValue(of(CONFIG_STATE_DATA));
jest.spyOn(configState, 'getOne').mockImplementation((key) => {
vi.spyOn(configState, 'getAll').mockReturnValue(CONFIG_STATE_DATA);
vi.spyOn(configState, 'getAll$').mockReturnValue(of(CONFIG_STATE_DATA));
vi.spyOn(configState, 'getOne').mockImplementation((key) => {
if (key === 'localization') return CONFIG_STATE_DATA.localization;
return undefined;
});
jest.spyOn(configState, 'getOne$').mockImplementation((key) => {
vi.spyOn(configState, 'getOne$').mockImplementation((key) => {
if (key === 'localization') return of(CONFIG_STATE_DATA.localization);
return of(undefined);
});
jest.spyOn(configState, 'getDeep').mockImplementation((key) => {
vi.spyOn(configState, 'getDeep').mockImplementation((key) => {
if (key === 'localization.languages') return CONFIG_STATE_DATA.localization.languages;
if (key === 'test') return undefined;
return undefined;
});
jest.spyOn(configState, 'getDeep$').mockImplementation((key) => {
vi.spyOn(configState, 'getDeep$').mockImplementation((key) => {
if (key === 'localization.languages') return of(CONFIG_STATE_DATA.localization.languages);
return of(undefined);
});
jest.spyOn(configState, 'getFeature').mockImplementation((key) => {
vi.spyOn(configState, 'getFeature').mockImplementation((key) => {
if (key === 'Chat.Enable') return CONFIG_STATE_DATA.features.values['Chat.Enable'];
return undefined;
});
jest.spyOn(configState, 'getFeature$').mockImplementation((key) => {
vi.spyOn(configState, 'getFeature$').mockImplementation((key) => {
if (key === 'Chat.Enable') return of(CONFIG_STATE_DATA.features.values['Chat.Enable']);
return of(undefined);
});
jest.spyOn(configState, 'getSetting').mockImplementation((key) => {
vi.spyOn(configState, 'getSetting').mockImplementation((key) => {
if (key === 'Abp.Localization.DefaultLanguage') return CONFIG_STATE_DATA.setting.values['Abp.Localization.DefaultLanguage'];
return undefined;
});
jest.spyOn(configState, 'getSetting$').mockImplementation((key) => {
vi.spyOn(configState, 'getSetting$').mockImplementation((key) => {
if (key === 'Abp.Localization.DefaultLanguage') return of(CONFIG_STATE_DATA.setting.values['Abp.Localization.DefaultLanguage']);
return of(undefined);
});
jest.spyOn(configState, 'getSettings').mockImplementation((keyword) => {
vi.spyOn(configState, 'getSettings').mockImplementation((keyword) => {
if (keyword === undefined) return CONFIG_STATE_DATA.setting.values;
if (keyword === 'localization') return { 'Abp.Localization.DefaultLanguage': 'en' };
if (keyword === 'Localization') return { 'Abp.Localization.DefaultLanguage': 'en' };
return {};
});
jest.spyOn(configState, 'getSettings$').mockImplementation((keyword) => {
vi.spyOn(configState, 'getSettings$').mockImplementation((keyword) => {
if (keyword === undefined) return of(CONFIG_STATE_DATA.setting.values);
if (keyword === 'localization') return of({ 'Abp.Localization.DefaultLanguage': 'en' });
if (keyword === 'Localization') return of({ 'Abp.Localization.DefaultLanguage': 'en' });
return of({});
});
jest.spyOn(configState, 'getFeatures').mockImplementation((keys) => {
vi.spyOn(configState, 'getFeatures').mockImplementation((keys) => {
if (keys.includes('Chat.Enable')) {
return { 'Chat.Enable': 'True' };
}
return {};
});
jest.spyOn(configState, 'getFeatures$').mockImplementation((keys) => {
vi.spyOn(configState, 'getFeatures$').mockImplementation((keys) => {
if (keys.includes('Chat.Enable')) {
return of({ 'Chat.Enable': 'True' });
}
return of({});
});
jest.spyOn(configState, 'getFeatureIsEnabled').mockImplementation((key) => {
vi.spyOn(configState, 'getFeatureIsEnabled').mockImplementation((key) => {
if (key === 'Chat.Enable') return true;
return false;
});
jest.spyOn(configState, 'getFeatureIsEnabled$').mockImplementation((key) => {
vi.spyOn(configState, 'getFeatureIsEnabled$').mockImplementation((key) => {
if (key === 'Chat.Enable') return of(true);
return of(false);
});
jest.spyOn(configState, 'getGlobalFeatures').mockReturnValue({
vi.spyOn(configState, 'getGlobalFeatures').mockReturnValue({
enabledFeatures: ['Feature1', 'Feature2']
});
jest.spyOn(configState, 'getGlobalFeatures$').mockReturnValue(of({
vi.spyOn(configState, 'getGlobalFeatures$').mockReturnValue(of({
enabledFeatures: ['Feature1', 'Feature2']
}));
jest.spyOn(configState, 'getGlobalFeatureIsEnabled').mockImplementation((key) => {
vi.spyOn(configState, 'getGlobalFeatureIsEnabled').mockImplementation((key) => {
if (key === 'Feature1') return true;
return false;
});
jest.spyOn(configState, 'getGlobalFeatureIsEnabled$').mockImplementation((key) => {
vi.spyOn(configState, 'getGlobalFeatureIsEnabled$').mockImplementation((key) => {
if (key === 'Feature1') return of(true);
return of(false);
});

6
npm/ng-packs/packages/core/src/lib/tests/container.strategy.spec.ts

@ -7,7 +7,7 @@ import {
describe('ClearContainerStrategy', () => {
const containerRef = {
clear: jest.fn(),
clear: vi.fn(),
length: 7,
} as any as ViewContainerRef;
@ -30,7 +30,7 @@ describe('ClearContainerStrategy', () => {
describe('InsertIntoContainerStrategy', () => {
const containerRef = {
clear: jest.fn(),
clear: vi.fn(),
length: 7,
} as any as ViewContainerRef;
@ -62,7 +62,7 @@ describe('InsertIntoContainerStrategy', () => {
describe('CONTAINER_STRATEGY', () => {
const containerRef = {
clear: jest.fn(),
clear: vi.fn(),
length: 7,
} as any as ViewContainerRef;

5
npm/ng-packs/packages/core/src/lib/tests/content-projection.service.spec.ts

@ -1,10 +1,9 @@
import { Component, ComponentRef } from '@angular/core';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { ContentProjectionService } from '../services';
import { PROJECTION_STRATEGY } from '../strategies';
describe('ContentProjectionService', () => {
@Component({
@Component({
template: '<div class="foo">bar</div>',
})
class TestComponent {}

52
npm/ng-packs/packages/core/src/lib/tests/content.strategy.spec.ts

@ -1,3 +1,5 @@
import { Injector, runInInjectionContext } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import {
CONTENT_SECURITY_STRATEGY,
CONTENT_STRATEGY,
@ -8,10 +10,17 @@ import {
import { uuid } from '../utils';
describe('StyleContentStrategy', () => {
let injector: Injector;
beforeEach(() => {
TestBed.configureTestingModule({});
injector = TestBed.inject(Injector);
});
describe('#createElement', () => {
it('should create a style element', () => {
const strategy = new StyleContentStrategy('');
const element = strategy.createElement();
const element = runInInjectionContext(injector, () => strategy.createElement());
expect(element.tagName).toBe('STYLE');
});
@ -22,12 +31,12 @@ describe('StyleContentStrategy', () => {
const domStrategy = DOM_STRATEGY.PrependToHead();
const contentSecurityStrategy = CONTENT_SECURITY_STRATEGY.None();
contentSecurityStrategy.applyCSP = jest.fn((el: HTMLScriptElement) => {});
domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => {}) as any;
contentSecurityStrategy.applyCSP = vi.fn((el: HTMLScriptElement) => {});
domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {}) as any;
const strategy = new StyleContentStrategy('', domStrategy, contentSecurityStrategy);
strategy.createElement();
const element = strategy.insertElement();
runInInjectionContext(injector, () => strategy.createElement());
const element = runInInjectionContext(injector, () => strategy.insertElement());
expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element);
expect(domStrategy.insertElement).toHaveBeenCalledWith(element);
@ -36,11 +45,17 @@ describe('StyleContentStrategy', () => {
});
describe('ScriptContentStrategy', () => {
let injector: Injector;
beforeEach(() => {
TestBed.configureTestingModule({});
injector = TestBed.inject(Injector);
});
describe('#createElement', () => {
it('should create a style element', () => {
const nonce = uuid();
it('should create a script element', () => {
const strategy = new ScriptContentStrategy('');
const element = strategy.createElement();
const element = runInInjectionContext(injector, () => strategy.createElement());
expect(element.tagName).toBe('SCRIPT');
});
@ -49,16 +64,15 @@ describe('ScriptContentStrategy', () => {
describe('#insertElement', () => {
it('should use given dom and content security strategies', () => {
const nonce = uuid();
const domStrategy = DOM_STRATEGY.PrependToHead();
const contentSecurityStrategy = CONTENT_SECURITY_STRATEGY.Loose(nonce);
contentSecurityStrategy.applyCSP = jest.fn((el: HTMLScriptElement) => {});
domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => {}) as any;
contentSecurityStrategy.applyCSP = vi.fn((el: HTMLScriptElement) => {});
domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {}) as any;
const strategy = new ScriptContentStrategy('', domStrategy, contentSecurityStrategy);
const element = strategy.createElement();
strategy.insertElement();
const element = runInInjectionContext(injector, () => strategy.createElement());
runInInjectionContext(injector, () => strategy.insertElement());
expect(contentSecurityStrategy.applyCSP).toHaveBeenCalledWith(element);
expect(domStrategy.insertElement).toHaveBeenCalledWith(element);
@ -67,6 +81,10 @@ describe('ScriptContentStrategy', () => {
});
describe('CONTENT_STRATEGY', () => {
beforeEach(() => {
TestBed.configureTestingModule({});
});
test.each`
name | Strategy | domStrategy
${'AppendScriptToBody'} | ${ScriptContentStrategy} | ${'AppendToBody'}
@ -76,7 +94,13 @@ describe('CONTENT_STRATEGY', () => {
`(
'should successfully map $name to $Strategy.name with $domStrategy dom strategy',
({ name, Strategy, domStrategy }) => {
expect(CONTENT_STRATEGY[name]('')).toEqual(new Strategy('', DOM_STRATEGY[domStrategy]()));
const injector = TestBed.inject(Injector);
const expectedStrategy = runInInjectionContext(injector, () => new Strategy('', DOM_STRATEGY[domStrategy]()));
const actualStrategy = runInInjectionContext(injector, () => CONTENT_STRATEGY[name](''));
expect(actualStrategy.constructor).toBe(expectedStrategy.constructor);
expect(actualStrategy.content).toBe(expectedStrategy.content);
expect(actualStrategy['domStrategy'].constructor).toBe(expectedStrategy['domStrategy'].constructor);
},
);
});

2
npm/ng-packs/packages/core/src/lib/tests/context.strategy.spec.ts

@ -20,7 +20,7 @@ describe('ComponentContextStrategy', () => {
z: '',
},
changeDetectorRef: {
detectChanges: jest.fn(),
detectChanges: vi.fn(),
},
} as any),
);

26
npm/ng-packs/packages/core/src/lib/tests/date-utils.spec.ts

@ -1,6 +1,6 @@
import { ConfigStateService } from '../services';
import { getShortDateFormat, getShortDateShortTimeFormat, getShortTimeFormat } from '../utils';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { CORE_OPTIONS } from '../tokens/options.token';
import { HttpClient } from '@angular/common/http';
import { AbpApplicationConfigurationService } from '../proxy/volo/abp/asp-net-core/mvc/application-configurations/abp-application-configuration.service';
@ -41,40 +41,40 @@ describe('Date Utils', () => {
{
provide: HttpClient,
useValue: {
get: jest.fn(),
post: jest.fn(),
put: jest.fn(),
delete: jest.fn(),
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
},
},
{
provide: AbpApplicationConfigurationService,
useValue: {
get: jest.fn(),
get: vi.fn(),
},
},
{
provide: RestService,
useValue: {
request: jest.fn(),
request: vi.fn(),
},
},
{
provide: EnvironmentService,
useValue: {
getEnvironment: jest.fn(),
getEnvironment: vi.fn(),
},
},
{
provide: HttpErrorReporterService,
useValue: {
reportError: jest.fn(),
reportError: vi.fn(),
},
},
{
provide: ExternalHttpClient,
useValue: {
request: jest.fn(),
request: vi.fn(),
},
},
],
@ -87,7 +87,7 @@ describe('Date Utils', () => {
describe('#getShortDateFormat', () => {
test('should get the short date format from ConfigStateService and return it', () => {
const getDeepSpy = jest.spyOn(config, 'getDeep');
const getDeepSpy = vi.spyOn(config, 'getDeep');
getDeepSpy.mockReturnValueOnce(dateTimeFormat);
expect(getShortDateFormat(config)).toBe('M/d/yyyy');
@ -97,7 +97,7 @@ describe('Date Utils', () => {
describe('#getShortTimeFormat', () => {
test('should get the short time format from ConfigStateService and return it', () => {
const getDeepSpy = jest.spyOn(config, 'getDeep');
const getDeepSpy = vi.spyOn(config, 'getDeep');
getDeepSpy.mockReturnValueOnce(dateTimeFormat);
expect(getShortTimeFormat(config)).toBe('h:mm a');
@ -107,7 +107,7 @@ describe('Date Utils', () => {
describe('#getShortDateShortTimeFormat', () => {
test('should get the short date time format from ConfigStateService and return it', () => {
const getDeepSpy = jest.spyOn(config, 'getDeep');
const getDeepSpy = vi.spyOn(config, 'getDeep');
getDeepSpy.mockReturnValueOnce(dateTimeFormat);
expect(getShortDateShortTimeFormat(config)).toBe('M/d/yyyy h:mm a');

14
npm/ng-packs/packages/core/src/lib/tests/debounce.directive.spec.ts

@ -1,12 +1,12 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { timer , firstValueFrom } from 'rxjs';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { InputEventDebounceDirective } from '../directives/debounce.directive';
import { timer } from 'rxjs';
describe('InputEventDebounceDirective', () => {
let spectator: SpectatorDirective<InputEventDebounceDirective>;
let directive: InputEventDebounceDirective;
let input: HTMLInputElement;
const inputEventFn = jest.fn(() => {});
const inputEventFn = vi.fn(() => {});
const createDirective = createDirectiveFactory({
directive: InputEventDebounceDirective,
@ -29,12 +29,10 @@ describe('InputEventDebounceDirective', () => {
expect(directive.debounce).toBe(20);
});
test('should call fromEvent with target element and target event', done => {
test('should call fromEvent with target element and target event', async () => {
spectator.dispatchFakeEvent('input', 'input', true);
timer(0).subscribe(() => expect(inputEventFn).not.toHaveBeenCalled());
timer(21).subscribe(() => {
expect(inputEventFn).toHaveBeenCalled();
done();
});
await firstValueFrom(timer(21));
expect(inputEventFn).toHaveBeenCalled();
});
});

19
npm/ng-packs/packages/core/src/lib/tests/dom-insertion.service.spec.ts

@ -1,3 +1,4 @@
import { Injector, runInInjectionContext } from '@angular/core';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator';
import { DomInsertionService } from '../services';
import { CONTENT_STRATEGY } from '../strategies';
@ -14,28 +15,30 @@ describe('DomInsertionService', () => {
describe('#insertContent', () => {
it('should be able to insert given content', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content));
const injector = spectator.inject(Injector);
runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe(content);
});
it('should set a hash for the inserted content', () => {
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content));
const injector = spectator.inject(Injector);
runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
expect(spectator.service.has(content)).toBe(true);
});
it('should insert only once', () => {
expect(spectator.service.has(content)).toBe(false);
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content));
const injector = spectator.inject(Injector);
runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1);
expect(styleElements[0].textContent).toBe(content);
expect(spectator.service.has(content)).toBe(true);
spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content));
runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
styleElements = document.head.querySelectorAll('style');
expect(styleElements.length).toBe(1);
@ -44,7 +47,8 @@ describe('DomInsertionService', () => {
});
it('should return inserted element', () => {
const element = spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content));
const injector = spectator.inject(Injector);
const element = runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
expect(element.tagName).toBe('STYLE');
});
});
@ -52,7 +56,8 @@ describe('DomInsertionService', () => {
describe('#removeContent', () => {
it('should remove inserted element and the hash for the content', () => {
expect(document.head.querySelector('style')).toBeNull();
const element = spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content));
const injector = spectator.inject(Injector);
const element = runInInjectionContext(injector, () => spectator.service.insertContent(CONTENT_STRATEGY.AppendStyleToHead(content)));
expect(spectator.service.has(content)).toBe(true);
spectator.service.removeContent(element);

27
npm/ng-packs/packages/core/src/lib/tests/dom.strategy.spec.ts

@ -3,7 +3,7 @@ import { DOM_STRATEGY, DomStrategy } from '../strategies/dom.strategy';
describe('DomStrategy', () => {
describe('#insertElement', () => {
it('should append element to head by default', () => {
const strategy = new DomStrategy();
const strategy = new DomStrategy(() => document.head);
const element = document.createElement('script');
strategy.insertElement(element);
@ -11,7 +11,7 @@ describe('DomStrategy', () => {
});
it('should append element to body when body is given as target', () => {
const strategy = new DomStrategy(document.body);
const strategy = new DomStrategy(() => document.body);
const element = document.createElement('script');
strategy.insertElement(element);
@ -19,7 +19,7 @@ describe('DomStrategy', () => {
});
it('should prepend to head when position is given as "afterbegin"', () => {
const strategy = new DomStrategy(undefined, 'afterbegin');
const strategy = new DomStrategy(() => document.head, 'afterbegin');
const element = document.createElement('script');
strategy.insertElement(element);
@ -37,13 +37,18 @@ describe('DOM_STRATEGY', () => {
});
test.each`
name | target | position
${'AfterElement'} | ${div} | ${'afterend'}
${'AppendToBody'} | ${document.body} | ${'beforeend'}
${'AppendToHead'} | ${document.head} | ${'beforeend'}
${'BeforeElement'} | ${div} | ${'beforebegin'}
${'PrependToHead'} | ${document.head} | ${'afterbegin'}
`('should successfully map $name to CrossOriginStrategy', ({ name, target, position }) => {
expect(DOM_STRATEGY[name](target)).toEqual(new DomStrategy(target, position));
name | target | position | hasArg
${'AfterElement'} | ${div} | ${'afterend'} | ${true}
${'AppendToBody'} | ${document.body} | ${'beforeend'} | ${false}
${'AppendToHead'} | ${document.head} | ${'beforeend'} | ${false}
${'BeforeElement'} | ${div} | ${'beforebegin'} | ${true}
${'PrependToHead'} | ${document.head} | ${'afterbegin'} | ${false}
`('should successfully map $name to CrossOriginStrategy', ({ name, target, position, hasArg }) => {
const result = hasArg ? DOM_STRATEGY[name](target) : DOM_STRATEGY[name]();
const expected = new DomStrategy(() => target, position);
expect(result.position).toBe(expected.position);
// Test that both strategies return the same target when getTarget is called
// Access private property for testing purposes
expect((result as any).getTarget()).toBe((expected as any).getTarget());
});
});

21
npm/ng-packs/packages/core/src/lib/tests/dynamic-layout.component.spec.ts

@ -1,7 +1,7 @@
import { HttpClient } from '@angular/common/http';
import { Component, NgModule, inject as inject_1 } from '@angular/core';
import { Component, inject as inject_1 } from '@angular/core';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/vitest';
import { DynamicLayoutComponent, RouterOutletComponent } from '../components';
import { eLayoutType } from '../enums/common';
import { ABP } from '../models';
@ -68,16 +68,23 @@ describe('DynamicLayoutComponent', () => {
const createComponent = createRoutingFactory({
component: RouterOutletComponent,
stubsEnabled: false,
imports: [DummyComponent, RouterModule, DummyApplicationLayoutComponent, DummyAccountLayoutComponent, DummyEmptyLayoutComponent, DynamicLayoutComponent],
imports: [
DummyComponent,
RouterModule,
DummyApplicationLayoutComponent,
DummyAccountLayoutComponent,
DummyEmptyLayoutComponent,
DynamicLayoutComponent,
],
mocks: [AbpApplicationConfigurationService, HttpClient],
providers: [
{
provide: RoutesService,
useValue: {
add: jest.fn(),
flat$: { pipe: jest.fn() },
tree$: { pipe: jest.fn() },
visible$: { pipe: jest.fn() },
add: vi.fn(),
flat$: { pipe: vi.fn() },
tree$: { pipe: vi.fn() },
visible$: { pipe: vi.fn() },
},
},
ReplaceableComponentsService,

8
npm/ng-packs/packages/core/src/lib/tests/environment-utils.spec.ts

@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http';
import { Component, Injector } from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import { BehaviorSubject } from 'rxjs';
import { Environment, RemoteEnv } from '../models/environment';
import { EnvironmentService } from '../services/environment.service';
@ -77,11 +77,11 @@ describe('EnvironmentUtils', () => {
function setupTestAndRun(strategy: Pick<RemoteEnv, 'mergeStrategy'>, expectedValue) {
const injector = spectator.inject(Injector);
const injectorSpy = jest.spyOn(injector, 'get');
const injectorSpy = vi.spyOn(injector, 'get');
const http = spectator.inject(HttpClient);
const requestSpy = jest.spyOn(http, 'request');
const requestSpy = vi.spyOn(http, 'request');
const environmentService = spectator.inject(EnvironmentService);
const setStateSpy = jest.spyOn(environmentService, 'setState');
const setStateSpy = vi.spyOn(environmentService, 'setState');
injectorSpy.mockReturnValueOnce(environmentService);
injectorSpy.mockReturnValueOnce(http);

25
npm/ng-packs/packages/core/src/lib/tests/environment.service.spec.ts

@ -1,5 +1,5 @@
import { waitForAsync } from '@angular/core/testing';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { firstValueFrom } from 'rxjs';
import { Environment } from '../models/environment';
import { EnvironmentService } from '../services/environment.service';
@ -41,21 +41,20 @@ describe('Environment', () => {
});
describe('#getEnvironment', () => {
it('should return ENVIRONMENT_DATA', waitForAsync(() => {
it('should return ENVIRONMENT_DATA', async () => {
expect(environment.getEnvironment()).toEqual(ENVIRONMENT_DATA);
environment.getEnvironment$().subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA));
}));
const data = await firstValueFrom(environment.getEnvironment$());
expect(data).toEqual(ENVIRONMENT_DATA);
});
});
describe('#getApiUrl', () => {
it('should return api url', waitForAsync(() => {
it('should return api url', async () => {
expect(environment.getApiUrl('default')).toEqual(ENVIRONMENT_DATA.apis.default.url);
environment
.getApiUrl$('other')
.subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.other.url));
environment
.getApiUrl$('yetAnother')
.subscribe(data => expect(data).toEqual(ENVIRONMENT_DATA.apis.default.url));
}));
const otherData = await firstValueFrom(environment.getApiUrl$('other'));
expect(otherData).toEqual(ENVIRONMENT_DATA.apis.other.url);
const yetAnotherData = await firstValueFrom(environment.getApiUrl$('yetAnother'));
expect(yetAnotherData).toEqual(ENVIRONMENT_DATA.apis.default.url);
});
});
});

35
npm/ng-packs/packages/core/src/lib/tests/for.directive.spec.ts

@ -1,4 +1,4 @@
import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/jest';
import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/vitest';
import { ForDirective } from '../directives/for.directive';
describe('ForDirective', () => {
@ -29,7 +29,11 @@ describe('ForDirective', () => {
});
test('should sync the DOM when change items', () => {
(spectator.hostComponent as any).items = [10, 11, 12];
directive.items = [10, 11, 12];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
const elements = spectator.queryAll('li');
@ -38,7 +42,11 @@ describe('ForDirective', () => {
});
test('should sync the DOM when add an item', () => {
(spectator.hostComponent as any).items = [...items, 6];
directive.items = [...items, 6];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
const elements = spectator.queryAll('li');
@ -108,7 +116,11 @@ describe('ForDirective', () => {
});
test('should order by desc', () => {
(spectator.hostComponent as any).orderDir = 'DESC';
directive.orderDir = 'DESC';
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
const elements = spectator.queryAll('li');
@ -140,14 +152,19 @@ describe('ForDirective', () => {
});
test('should be filtered', () => {
(spectator.hostComponent as any).filterVal = 'volo';
directive.filterVal = 'volo';
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
expect(spectator.query('li')).toHaveText('volo');
});
test('should not show an element when filter value not match to any text', () => {
(spectator.hostComponent as any).filterVal = 'volos';
directive.filterVal = 'volos';
directive.ngOnChanges();
spectator.detectChanges();
const elements = spectator.queryAll('li');
@ -183,7 +200,11 @@ describe('ForDirective', () => {
expect(spectator.query('ul')).toHaveText('No records found');
expect(spectator.queryAll('li')).toHaveLength(0);
(spectator.hostComponent as any).items = [0];
directive.items = [0];
directive['vcRef'].clear();
directive['lastItemsRef'] = null;
directive['differ'] = null;
directive.ngOnChanges();
spectator.detectChanges();
expect(spectator.query('ul')).not.toHaveText('No records found');

21
npm/ng-packs/packages/core/src/lib/tests/form-submit.directive.spec.ts

@ -1,14 +1,14 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { FormSubmitDirective } from '../directives/form-submit.directive';
import { FormsModule, ReactiveFormsModule, FormGroup } from '@angular/forms';
import { timer } from 'rxjs';
import { timer, firstValueFrom } from 'rxjs';
describe('FormSubmitDirective', () => {
let spectator: SpectatorDirective<FormSubmitDirective>;
let directive: FormSubmitDirective;
const formGroup = new FormGroup({});
const submitEventFn = jest.fn(() => {});
const submitEventFn = vi.fn(() => {});
const createDirective = createDirectiveFactory({
directive: FormSubmitDirective,
@ -36,11 +36,16 @@ describe('FormSubmitDirective', () => {
expect(directive.debounce).toBe(20);
});
test('should dispatch submit event on keyup event triggered after given debounce time', done => {
spectator.dispatchKeyboardEvent('form', 'keyup', 'Enter');
timer(directive.debounce + 10).subscribe(() => {
expect(submitEventFn).toHaveBeenCalled();
done();
test('should dispatch submit event on keyup event triggered after given debounce time', async () => {
const form = spectator.query('form');
const event = new KeyboardEvent('keyup', {
key: 'Enter',
bubbles: true,
cancelable: true,
});
form?.dispatchEvent(event);
timer(0).subscribe(() => expect(submitEventFn).not.toHaveBeenCalled());
await firstValueFrom(timer(directive.debounce + 10));
expect(submitEventFn).toHaveBeenCalled();
});
});

13
npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts

@ -1,17 +1,13 @@
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import { Component } from '@angular/core';
import { EnvironmentService } from '../services/environment.service';
import { AuthService } from '../abstracts/auth.service';
import {SessionStateService} from '../services/session-state.service';
import { ConfigStateService } from '../services/config-state.service';
import { AuthService } from '../abstracts/auth.service';
import { CORE_OPTIONS } from '../tokens/options.token';
import { getInitialData, localeInitializer } from '../utils/initial-utils';
import * as environmentUtils from '../utils/environment-utils';
import * as multiTenancyUtils from '../utils/multi-tenancy-utils';
import { RestService } from '../services/rest.service';
import { CHECK_AUTHENTICATION_STATE_FN_KEY } from '../tokens/check-authentication-state';
import { Component, Injector } from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { AbpApplicationConfigurationService, SessionStateService } from '@abp/ng.core';
import { ApplicationConfigurationDto } from '@abp/ng.core';
const environment = { oAuthConfig: { issuer: 'test' } };
@ -28,7 +24,6 @@ describe('InitialUtils', () => {
mocks: [
EnvironmentService,
ConfigStateService,
AbpApplicationConfigurationService,
AuthService,
SessionStateService,
RestService,

16
npm/ng-packs/packages/core/src/lib/tests/internal-store.spec.ts

@ -124,18 +124,20 @@ describe('Internal Store', () => {
});
describe('sliceUpdate', () => {
it('should return slice of update$ based on selector', done => {
it('should return slice of update$ based on selector', () => {
const store = new InternalStore(mockInitialState);
const onQux$ = store.sliceUpdate(state => state.foo.bar.qux);
onQux$.pipe(take(1)).subscribe(value => {
expect(value).toEqual(deepPatch2.foo.bar.qux);
done();
});
return new Promise<void>(resolve => {
onQux$.pipe(take(1)).subscribe(value => {
expect(value).toEqual(deepPatch2.foo.bar.qux);
resolve();
});
store.deepPatch(deepPatch1);
store.deepPatch(deepPatch2);
store.deepPatch(deepPatch1);
store.deepPatch(deepPatch2);
});
});
});

209
npm/ng-packs/packages/core/src/lib/tests/internet-connection.service.spec.ts

@ -1,100 +1,109 @@
import { TestBed} from '@angular/core/testing';
import { DOCUMENT } from '@angular/common';
import { InternetConnectionService } from '../services/internet-connection-service';
import { first } from 'rxjs';
let service: InternetConnectionService;
describe('Internet connection when disconnected', () => {
const events = {};
const addEventListener = jest.fn((event, callback) => {
events[event] = callback;
});
const mockDocument = { defaultView: {navigator: {onLine: false}, addEventListener } }
beforeAll(() => {
TestBed.configureTestingModule({
providers:[{provide:DOCUMENT, useValue: mockDocument}]
})
service = TestBed.inject(InternetConnectionService);
});
it('document should be created', () => {
expect(service.document).toEqual(mockDocument);
});
it('signal value should be false', () => {
expect(service.networkStatus()).toEqual(false);
});
it('observable value should be false',
(done: any) => {
service.networkStatus$.pipe(first()).subscribe(value => {
expect(value).toBe(false)
done();
});
});
test.each(['offline','online'])('should addEventListener for %p, event',(v)=>{
expect(events[v]).toBeTruthy()
})
test.each([['offline',false],["online",true]])('when %p called ,then signal value must be %p',(eventName,value)=>{
events[eventName]()
expect(service.networkStatus()).toEqual(value);
})
test.each([['offline',false],["online",true]])('when %p called,then observable must return %p',(eventName,value)=>{
events[eventName]()
service.networkStatus$.subscribe(val=>{
expect(val).toEqual(value)
})
})
});
describe('when connection value changes for signals', () => {
const events = {};
const addEventListener = jest.fn((event, callback) => {
events[event] = callback;
});
const mockDocument = { defaultView: {navigator: {onLine: false}, addEventListener } }
beforeAll(() => {
TestBed.configureTestingModule({
providers:[{provide:DOCUMENT, useValue: mockDocument}]
})
service = TestBed.inject(InternetConnectionService);
});
it('signal value must be false when offline event is called while internet is connected', () => {
events['online']()
expect(service.networkStatus()).toEqual(true);
events['offline']()
expect(service.networkStatus()).toEqual(false);
});
it('signal value must be true when online event is called while internet is disconnected', () => {
events['offline']()
expect(service.networkStatus()).toEqual(false);
events['online']()
expect(service.networkStatus()).toEqual(true);
});
it('observable value must be false when offline event is called while internet is connected', (done:any) => {
events['online']()
events['offline']()
service.networkStatus$.subscribe(val=>{
expect(val).toEqual(false)
done()
})
});
it('observable value must be true when online event is called while internet is disconnected', (done:any) => {
events['offline']()
events['online']()
service.networkStatus$.subscribe(val=>{
console.log(val);
expect(val).toEqual(true)
done()
})
});
});
import { TestBed } from '@angular/core/testing';
import { DOCUMENT } from '@angular/common';
import { InternetConnectionService } from '../services/internet-connection-service';
import { first, firstValueFrom, skip } from 'rxjs';
let service: InternetConnectionService;
describe('Internet connection when disconnected', () => {
const events = {};
const addEventListener = vi.fn((event, callback) => {
events[event] = callback;
});
const mockDocument = { defaultView: { navigator: { onLine: false }, addEventListener } };
beforeAll(() => {
TestBed.configureTestingModule({
providers: [{ provide: DOCUMENT, useValue: mockDocument }],
});
service = TestBed.inject(InternetConnectionService);
});
it('document should be created', () => {
expect(service.document).toEqual(mockDocument);
});
it('signal value should be false', () => {
expect(service.networkStatus()).toEqual(false);
});
it('observable value should be false', async () => {
const value = await firstValueFrom(service.networkStatus$.pipe(first()));
expect(value).toBe(false);
});
test.each(['offline', 'online'])('should addEventListener for %p, event', v => {
expect(events[v]).toBeTruthy();
});
test.each([
['offline', false],
['online', true],
])('when %p called ,then signal value must be %p', (eventName, value) => {
events[eventName]();
expect(service.networkStatus()).toEqual(value);
});
test.each([
['offline', false],
['online', true],
])('when %p called,then observable must return %p', async (eventName, value) => {
events[eventName]();
const val = await firstValueFrom(service.networkStatus$);
expect(val).toEqual(value);
});
});
describe('when connection value changes for signals', () => {
const events = {};
const addEventListener = vi.fn((event, callback) => {
events[event] = callback;
});
const mockDocument = { defaultView: { navigator: { onLine: false }, addEventListener } };
beforeAll(() => {
TestBed.configureTestingModule({
providers: [{ provide: DOCUMENT, useValue: mockDocument }],
});
service = TestBed.inject(InternetConnectionService);
});
it('signal value must be false when offline event is called while internet is connected', () => {
events['online']();
expect(service.networkStatus()).toEqual(true);
events['offline']();
expect(service.networkStatus()).toEqual(false);
});
it('signal value must be true when online event is called while internet is disconnected', () => {
events['offline']();
expect(service.networkStatus()).toEqual(false);
events['online']();
expect(service.networkStatus()).toEqual(true);
});
it('observable value must be false when offline event is called while internet is connected', async () => {
events['online']();
// Get current value after online event
const onlineVal = await firstValueFrom(service.networkStatus$);
expect(onlineVal).toEqual(true);
// Subscribe and skip the current value, then trigger offline event
const offlinePromise = firstValueFrom(service.networkStatus$.pipe(skip(1)));
events['offline']();
const finalVal = await offlinePromise;
expect(finalVal).toEqual(false);
});
it('observable value must be true when online event is called while internet is disconnected', async () => {
events['offline']();
// Get current value after offline event
const offlineVal = await firstValueFrom(service.networkStatus$);
expect(offlineVal).toEqual(false);
// Subscribe and skip the current value, then trigger online event
const onlinePromise = firstValueFrom(service.networkStatus$.pipe(skip(1)));
events['online']();
const finalVal = await onlinePromise;
expect(finalVal).toEqual(true);
});
});

106
npm/ng-packs/packages/core/src/lib/tests/lazy-load-utils.spec.ts

@ -6,12 +6,12 @@ import { fromLazyLoad } from '../utils/lazy-load-utils';
describe('Lazy Load Utils', () => {
describe('#fromLazyLoad', () => {
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
it('should append to head by default', () => {
const element = document.createElement('link');
const spy = jest.spyOn(document.head, 'insertAdjacentElement');
const spy = vi.spyOn(document.head, 'insertAdjacentElement');
fromLazyLoad(element);
expect(spy).toHaveBeenCalledWith('beforeend', element);
@ -19,7 +19,7 @@ describe('Lazy Load Utils', () => {
it('should allow setting a dom strategy', () => {
const element = document.createElement('link');
const spy = jest.spyOn(document.head, 'insertAdjacentElement');
const spy = vi.spyOn(document.head, 'insertAdjacentElement');
fromLazyLoad(element, DOM_STRATEGY.PrependToHead());
expect(spy).toHaveBeenCalledWith('afterbegin', element);
@ -52,61 +52,73 @@ describe('Lazy Load Utils', () => {
expect(element.getAttribute('integrity')).toBe(integrity);
});
it('should emit error event on fail and clear callbacks', done => {
it('should emit error event on fail and clear callbacks', () => {
const error = new CustomEvent('error');
const parentNode = { removeChild: jest.fn() };
const parentNode = { removeChild: vi.fn() };
const element = { parentNode } as any as HTMLLinkElement;
fromLazyLoad(
element,
{
insertElement(el: HTMLLinkElement) {
expect(el).toBe(element);
setTimeout(() => {
el.onerror(error);
}, 0);
return new Promise<void>((resolve, reject) => {
fromLazyLoad(
element,
{
insertElement(el: HTMLLinkElement) {
expect(el).toBe(element);
setTimeout(() => {
el.onerror(error);
}, 0);
},
} as DomStrategy,
{
setCrossOrigin(_: HTMLLinkElement) {},
} as CrossOriginStrategy,
).subscribe({
error: value => {
try {
expect(value).toBe(error);
expect(parentNode.removeChild).toHaveBeenCalledWith(element);
expect(element.onerror).toBeNull();
resolve();
} catch (e) {
reject(e);
}
},
} as DomStrategy,
{
setCrossOrigin(_: HTMLLinkElement) {},
} as CrossOriginStrategy,
).subscribe({
error: value => {
expect(value).toBe(error);
expect(parentNode.removeChild).toHaveBeenCalledWith(element);
expect(element.onerror).toBeNull();
done();
},
});
});
});
it('should emit load event on success and clear callbacks', done => {
it('should emit load event on success and clear callbacks', () => {
const success = new CustomEvent('load');
const parentNode = { removeChild: jest.fn() };
const parentNode = { removeChild: vi.fn() };
const element = { parentNode } as any as HTMLLinkElement;
fromLazyLoad(
element,
{
insertElement(el: HTMLLinkElement) {
expect(el).toBe(element);
setTimeout(() => {
el.onload(success);
}, 0);
return new Promise<void>((resolve, reject) => {
fromLazyLoad(
element,
{
insertElement(el: HTMLLinkElement) {
expect(el).toBe(element);
setTimeout(() => {
el.onload(success);
}, 0);
},
} as DomStrategy,
{
setCrossOrigin(_: HTMLLinkElement) {},
} as CrossOriginStrategy,
).subscribe({
next: value => {
try {
expect(value).toBe(success);
expect(parentNode.removeChild).not.toHaveBeenCalled();
expect(element.onload).toBeNull();
resolve();
} catch (e) {
reject(e);
}
},
} as DomStrategy,
{
setCrossOrigin(_: HTMLLinkElement) {},
} as CrossOriginStrategy,
).subscribe({
next: value => {
expect(value).toBe(success);
expect(parentNode.removeChild).not.toHaveBeenCalled();
expect(element.onload).toBeNull();
done();
},
});
});
});
});

10
npm/ng-packs/packages/core/src/lib/tests/lazy-load.service.spec.ts

@ -1,9 +1,7 @@
import { of, throwError } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { LazyLoadService } from '../services/lazy-load.service';
import { ScriptLoadingStrategy } from '../strategies/loading.strategy';
import { ResourceWaitService } from '../services/resource-wait.service';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
describe('LazyLoadService', () => {
let spectator: SpectatorService<LazyLoadService>;
@ -16,8 +14,8 @@ describe('LazyLoadService', () => {
{
provide: ResourceWaitService,
useValue: {
wait: jest.fn(),
addResource: jest.fn(),
wait: vi.fn(),
addResource: vi.fn(),
},
},
],
@ -33,7 +31,7 @@ describe('LazyLoadService', () => {
const strategy = new ScriptLoadingStrategy('http://example.com/');
afterEach(() => {
jest.clearAllMocks();
vi.clearAllMocks();
});
it('should create service successfully', () => {

117
npm/ng-packs/packages/core/src/lib/tests/list.service.spec.ts

@ -1,5 +1,5 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { of, firstValueFrom } from 'rxjs';
import { bufferCount, take } from 'rxjs/operators';
import { ABP } from '../models';
import { ListService, QueryStreamCreatorCallback } from '../services/list.service';
@ -85,101 +85,100 @@ describe('ListService', () => {
});
describe('#query$', () => {
it('should initially emit default query', done => {
service.query$.pipe(take(1)).subscribe(query => {
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
done();
it('should initially emit default query', async () => {
const query = await firstValueFrom(service.query$.pipe(take(1)));
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
});
it('should emit a query based on params set', done => {
it('should emit a query based on params set', async () => {
service.filter = 'foo';
service.sortKey = 'bar';
service.sortOrder = 'baz';
service.maxResultCount = 20;
service.page = 9;
service.query$.pipe(take(1)).subscribe(query => {
expect(query).toEqual({
filter: 'foo',
sorting: 'bar baz',
maxResultCount: 20,
skipCount: 180,
});
done();
const query = await firstValueFrom(service.query$.pipe(take(1)));
expect(query).toEqual({
filter: 'foo',
sorting: 'bar baz',
maxResultCount: 20,
skipCount: 180,
});
});
});
describe('#hookToQuery', () => {
it('should call given callback with the query', done => {
it('should call given callback with the query', async () => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 });
service.hookToQuery(callback).subscribe(({ items: [query] }) => {
expect(query).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
done();
const result = await firstValueFrom(service.hookToQuery(callback));
expect(result.items[0]).toEqual({
filter: undefined,
maxResultCount: 10,
skipCount: 0,
sorting: undefined,
});
});
it('should emit isLoading as side effect', done => {
it('should emit isLoading as side effect', async () => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 });
service.isLoading$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => {
expect(idle).toBe(false);
expect(init).toBe(true);
expect(end).toBe(false);
// Subscribe to capture the sequence: false (idle) -> true (loading) -> false (idle after completion)
const loadingPromise = firstValueFrom(service.isLoading$.pipe(bufferCount(3)));
const hookSubscription = service.hookToQuery(callback).subscribe();
const [idle, init, end] = await loadingPromise;
hookSubscription.unsubscribe();
done();
});
service.hookToQuery(callback).subscribe();
expect(idle).toBe(false);
expect(init).toBe(true);
expect(end).toBe(false);
});
it('should emit requestStatus as side effect', done => {
it('should emit requestStatus as side effect', async () => {
const callback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query =>
of({ items: [query], totalCount: 1 });
service.requestStatus$.pipe(bufferCount(3)).subscribe(([idle, init, end]) => {
expect(idle).toBe('idle');
expect(init).toBe('loading');
expect(end).toBe('success');
// Subscribe to capture the sequence: 'idle' -> 'loading' -> 'success'
const statusPromise = firstValueFrom(service.requestStatus$.pipe(bufferCount(3)));
const hookSubscription = service.hookToQuery(callback).subscribe();
const [idle, init, end] = await statusPromise;
hookSubscription.unsubscribe();
done();
});
service.hookToQuery(callback).subscribe();
expect(idle).toBe('idle');
expect(init).toBe('loading');
expect(end).toBe('success');
});
it('should emit error requestStatus as side effect and stop processing', done => {
it('should emit error requestStatus as side effect and stop processing', async () => {
const errCallback: QueryStreamCreatorCallback<ABP.PageQueryParams> = query => {
throw Error('A server error occurred');
};
service.requestStatus$.pipe(bufferCount(3)).subscribe(([idle, loading, error]) => {
expect(idle).toBe('idle');
expect(loading).toBe('loading');
expect(error).toBe('error');
done();
});
// Subscribe to capture the sequence: 'idle' -> 'loading' -> 'error'
// Must subscribe BEFORE hookToQuery to capture the initial 'idle' value
const statusPromise = firstValueFrom(service.requestStatus$.pipe(bufferCount(3)));
service.hookToQuery(errCallback).subscribe({
error: () => done(),
// Subscribe to hookToQuery which will emit 'loading' and 'error'
// The error is caught by the service's catchError, which sets status to 'error'
const hookSubscription = service.hookToQuery(errCallback).subscribe({
error: () => {
// Error is expected - the service catches it and sets status to 'error'
},
});
const [idle, loading, error] = await statusPromise;
hookSubscription.unsubscribe();
expect(idle).toBe('idle');
expect(loading).toBe('loading');
expect(error).toBe('error');
});
});
});

40
npm/ng-packs/packages/core/src/lib/tests/loading.strategy.spec.ts

@ -1,3 +1,4 @@
import { firstValueFrom } from 'rxjs';
import { CROSS_ORIGIN_STRATEGY } from '../strategies/cross-origin.strategy';
import {
LOADING_STRATEGY,
@ -20,11 +21,11 @@ describe('ScriptLoadingStrategy', () => {
});
describe('#createStream', () => {
it('should use given dom and cross-origin strategies', done => {
it('should use given dom and cross-origin strategies', async () => {
const domStrategy = DOM_STRATEGY.PrependToHead();
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials();
domStrategy.insertElement = jest.fn((el: HTMLScriptElement) => {
domStrategy.insertElement = vi.fn((el: HTMLScriptElement) => {
setTimeout(() => {
el.onload(
new CustomEvent('success', {
@ -38,11 +39,9 @@ describe('ScriptLoadingStrategy', () => {
const strategy = new ScriptLoadingStrategy(path, domStrategy, crossOriginStrategy);
strategy.createStream<CustomEvent>().subscribe(event => {
expect(strategy.element.tagName).toBe('SCRIPT');
expect(event.detail.crossOrigin).toBe('use-credentials');
done();
});
const event = await firstValueFrom(strategy.createStream<CustomEvent>());
expect(strategy.element.tagName).toBe('SCRIPT');
expect(event.detail.crossOrigin).toBe('use-credentials');
});
});
});
@ -60,11 +59,11 @@ describe('StyleLoadingStrategy', () => {
});
describe('#createStream', () => {
it('should use given dom and cross-origin strategies', done => {
it('should use given dom and cross-origin strategies', async () => {
const domStrategy = DOM_STRATEGY.PrependToHead();
const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.UseCredentials();
domStrategy.insertElement = jest.fn((el: HTMLLinkElement) => {
domStrategy.insertElement = vi.fn((el: HTMLLinkElement) => {
setTimeout(() => {
el.onload(
new CustomEvent('success', {
@ -78,11 +77,9 @@ describe('StyleLoadingStrategy', () => {
const strategy = new StyleLoadingStrategy(path, domStrategy, crossOriginStrategy);
strategy.createStream<CustomEvent>().subscribe(event => {
expect(strategy.element.tagName).toBe('LINK');
expect(event.detail.crossOrigin).toBe('use-credentials');
done();
});
const event = await firstValueFrom(strategy.createStream<CustomEvent>());
expect(strategy.element.tagName).toBe('LINK');
expect(event.detail.crossOrigin).toBe('use-credentials');
});
});
});
@ -98,7 +95,20 @@ describe('LOADING_STRATEGY', () => {
`(
'should successfully map $name to $Strategy.name with $domStrategy dom strategy',
({ name, Strategy, domStrategy }) => {
expect(LOADING_STRATEGY[name](path)).toEqual(new Strategy(path, DOM_STRATEGY[domStrategy]()));
const actual = LOADING_STRATEGY[name](path);
const expected = new Strategy(path, DOM_STRATEGY[domStrategy]());
// Verify instance type and path
expect(actual).toBeInstanceOf(Strategy);
expect(actual.path).toBe(expected.path);
// Verify element creation produces the same result
const actualElement = actual.createElement();
const expectedElement = expected.createElement();
expect(actualElement.tagName).toBe(expectedElement.tagName);
expect(actualElement.src || actualElement.href).toBe(
expectedElement.src || expectedElement.href,
);
},
);
});

12
npm/ng-packs/packages/core/src/lib/tests/local-storage.service.spec.ts

@ -15,37 +15,37 @@ describe('LocalStorageService', () => {
});
it('should be called getItem', () => {
const spy = jest.spyOn(service, 'getItem');
const spy = vi.spyOn(service, 'getItem');
service.getItem('test');
expect(spy).toHaveBeenCalled();
});
it('should be called setItem', () => {
const spy = jest.spyOn(service, 'setItem');
const spy = vi.spyOn(service, 'setItem');
service.setItem('test', 'value');
expect(spy).toHaveBeenCalled();
});
it('should be called removeItem', () => {
const spy = jest.spyOn(service, 'removeItem');
const spy = vi.spyOn(service, 'removeItem');
service.removeItem('test');
expect(spy).toHaveBeenCalled();
});
it('should be called clear', () => {
const spy = jest.spyOn(service, 'clear');
const spy = vi.spyOn(service, 'clear');
service.clear();
expect(spy).toHaveBeenCalled();
});
it('should be called key', () => {
const spy = jest.spyOn(service, 'key');
const spy = vi.spyOn(service, 'key');
service.key(0);
expect(spy).toHaveBeenCalled();
});
it('should be called length', () => {
const spy = jest.spyOn(service, 'length', 'get');
const spy = vi.spyOn(service, 'length', 'get');
service.length;
expect(spy).toHaveBeenCalled();
});

2
npm/ng-packs/packages/core/src/lib/tests/locale.provider.spec.ts

@ -1,5 +1,5 @@
import { Component, LOCALE_ID } from '@angular/core';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/vitest';
import { differentLocales } from '../constants/different-locales';
import { LocaleId } from '../providers/locale.provider';
import { LocalizationService } from '../services/localization.service';

4
npm/ng-packs/packages/core/src/lib/tests/localization.pipe.spec.ts

@ -1,4 +1,4 @@
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/vitest';
import { LocalizationPipe } from '../pipes/localization.pipe';
import { LocalizationService } from '../services/localization.service';
@ -19,7 +19,7 @@ describe('LocalizationPipe', () => {
});
it('should call getLocalization selector', () => {
const translateSpy = jest.spyOn(localizationService, 'instant');
const translateSpy = vi.spyOn(localizationService, 'instant');
pipe.transform('test', '1', '2');
pipe.transform('test2', ['3', '4'] as any);

22
npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts

@ -1,4 +1,4 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { Subject } from 'rxjs';
import { LocalizationService } from '../services/localization.service';
import { SessionStateService } from '../services/session-state.service';
@ -18,26 +18,26 @@ describe('LocalizationService', () => {
{
provide: SessionStateService,
useValue: {
getLanguage: jest.fn(() => 'en'),
setLanguage: jest.fn(),
getLanguage$: jest.fn(() => new Subject()),
onLanguageChange$: jest.fn(() => new Subject()),
getLanguage: vi.fn(() => 'en'),
setLanguage: vi.fn(),
getLanguage$: vi.fn(() => new Subject()),
onLanguageChange$: vi.fn(() => new Subject()),
},
},
{
provide: ConfigStateService,
useValue: {
getOne: jest.fn(),
refreshAppState: jest.fn(),
getDeep: jest.fn(),
getDeep$: jest.fn(() => new Subject()),
getOne$: jest.fn(() => new Subject()),
getOne: vi.fn(),
refreshAppState: vi.fn(),
getDeep: vi.fn(),
getDeep$: vi.fn(() => new Subject()),
getOne$: vi.fn(() => new Subject()),
},
},
{
provide: Injector,
useValue: {
get: jest.fn(),
get: vi.fn(),
},
},
],

25
npm/ng-packs/packages/core/src/lib/tests/multi-tenancy-utils.spec.ts

@ -1,5 +1,6 @@
import { Component } from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { Component, PLATFORM_ID } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import clone from 'just-clone';
import { of } from 'rxjs';
@ -10,6 +11,7 @@ import {
import { EnvironmentService, MultiTenancyService } from '../services';
import { parseTenantFromUrl } from '../utils';
import { TENANT_KEY } from '../tokens';
import { TENANT_NOT_FOUND_BY_NAME } from '../tokens/tenant-not-found-by-name';
const environment = {
production: false,
@ -68,9 +70,9 @@ describe('MultiTenancyUtils', () => {
test('should get the tenancyName, set replaced environment and call the findTenantByName method of AbpTenantService', async () => {
const environmentService = spectator.inject(EnvironmentService);
const multiTenancyService = spectator.inject(MultiTenancyService);
const setTenantByName = jest.spyOn(multiTenancyService, 'setTenantByName');
const getEnvironmentSpy = jest.spyOn(environmentService, 'getEnvironment');
const setStateSpy = jest.spyOn(environmentService, 'setState');
const setTenantByName = vi.spyOn(multiTenancyService, 'setTenantByName');
const getEnvironmentSpy = vi.spyOn(environmentService, 'getEnvironment');
const setStateSpy = vi.spyOn(environmentService, 'setState');
getEnvironmentSpy.mockReturnValue(clone(environment));
@ -85,10 +87,23 @@ describe('MultiTenancyUtils', () => {
setTenantByName.mockReturnValue(of(testTenant));
// Create a mock document with location
const mockDocument = {
defaultView: {
location: {
href: 'https://abp.volosoft.com/',
},
},
};
const mockInjector = {
get: arg => {
if (arg === EnvironmentService) return environmentService;
if (arg === MultiTenancyService) return multiTenancyService;
if (arg === PLATFORM_ID) return 'browser';
if (arg === DOCUMENT) return mockDocument;
if (arg === TENANT_NOT_FOUND_BY_NAME) return null;
return null;
},
};
await parseTenantFromUrl(mockInjector);

2
npm/ng-packs/packages/core/src/lib/tests/ng-model.component.spec.ts

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/vitest';
import { AbstractNgModelComponent } from '../abstracts';
@Component({

41
npm/ng-packs/packages/core/src/lib/tests/permission.directive.spec.ts

@ -1,8 +1,8 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { ChangeDetectorRef } from '@angular/core';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { Subject } from 'rxjs';
import { PermissionDirective } from '../directives/permission.directive';
import { PermissionService } from '../services/permission.service';
import { ChangeDetectorRef } from '@angular/core';
import { QUEUE_MANAGER } from '../tokens/queue.token';
describe('PermissionDirective', () => {
@ -13,16 +13,29 @@ describe('PermissionDirective', () => {
directive: PermissionDirective,
providers: [
{ provide: PermissionService, useValue: { getGrantedPolicy$: () => grantedPolicy$ } },
{ provide: QUEUE_MANAGER, useValue: { add: jest.fn() } },
{ provide: ChangeDetectorRef, useValue: { detectChanges: jest.fn() } },
{ provide: QUEUE_MANAGER, useValue: { add: vi.fn() } },
{ provide: ChangeDetectorRef, useValue: { detectChanges: vi.fn() } },
],
});
beforeEach(() => {
spectator = createDirective('<div [abpPermission]="permission" [abpPermissionRunChangeDetection]="runCD"></div>', {
hostProps: { permission: 'test', runCD: false },
});
spectator = createDirective(
'<div [abpPermission]="permission" [abpPermissionRunChangeDetection]="runCD"></div>',
{
hostProps: { permission: 'test', runCD: false },
},
);
directive = spectator.directive;
grantedPolicy$.next(false);
spectator.detectChanges();
});
afterEach(() => {
// Clean up subscriptions to prevent errors after test completion
if (directive?.subscription) {
directive.subscription.unsubscribe();
}
grantedPolicy$.next(false);
});
it('should create directive', () => {
@ -30,14 +43,20 @@ describe('PermissionDirective', () => {
});
it('should handle permission input', () => {
spectator.setHostInput({ permission: 'new-permission' });
spectator.detectChanges();
grantedPolicy$.next(false);
directive.condition = 'new-permission';
directive.ngOnChanges();
grantedPolicy$.next(true);
expect(directive).toBeTruthy();
expect(directive.condition).toBe('new-permission');
});
it('should handle runChangeDetection input', () => {
spectator.setHostInput({ runCD: true });
spectator.detectChanges();
grantedPolicy$.next(false);
directive.runChangeDetection = true;
directive.ngOnChanges();
grantedPolicy$.next(true);
expect(directive).toBeTruthy();
expect(directive.runChangeDetection).toBe(true);
});
});

45
npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts

@ -2,14 +2,14 @@ import { provideHttpClientTesting } from '@angular/common/http/testing';
import { provideHttpClient } from '@angular/common/http';
import { Component } from '@angular/core';
import { provideRouter, Route, Router } from '@angular/router';
import { createSpyObject, SpyObject } from '@ngneat/spectator/jest';
import { RouterTestingHarness } from '@angular/router/testing';
import { TestBed } from '@angular/core/testing';
import { createSpyObject, SpyObject } from '@ngneat/spectator/vitest';
import { of } from 'rxjs';
import { permissionGuard } from '../guards/permission.guard';
import { HttpErrorReporterService } from '../services/http-error-reporter.service';
import { PermissionService } from '../services/permission.service';
import { provideAbpCore, withOptions } from '../providers';
import { TestBed } from '@angular/core/testing';
import { RouterTestingHarness } from '@angular/router/testing';
import { AuthService } from '../abstracts';
@Component({ template: '' })
@ -62,28 +62,37 @@ describe('authGuard', () => {
{ provide: PermissionService, useValue: permissionService },
{ provide: HttpErrorReporterService, useValue: httpErrorReporter },
provideRouter(routes),
provideAbpCore(withOptions({
environment: {
apis: {
default: {
provideAbpCore(
withOptions({
environment: {
apis: {
default: {
url: 'http://localhost:4200',
},
},
application: {
baseUrl: 'http://localhost:4200',
name: 'TestApp',
},
remoteEnv: {
url: 'http://localhost:4200',
mergeStrategy: 'deepmerge',
},
},
application: {
baseUrl: 'http://localhost:4200',
name: 'TestApp',
},
remoteEnv: {
url: 'http://localhost:4200',
mergeStrategy: 'deepmerge',
},
},
registerLocaleFn: () => Promise.resolve(),
})),
registerLocaleFn: () => Promise.resolve(),
skipGetAppConfiguration: true,
}),
),
],
});
});
afterEach(async () => {
// Wait for any pending async operations to complete before teardown
await new Promise(resolve => setTimeout(resolve, 0));
TestBed.resetTestingModule();
});
it('should return true when the grantedPolicy is true', async () => {
permissionService.getGrantedPolicy$.andReturn(of(true));
await RouterTestingHarness.create('/dummy');

25
npm/ng-packs/packages/core/src/lib/tests/projection.strategy.spec.ts

@ -6,7 +6,7 @@ import {
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { createComponentFactory, Spectator } from '@ngneat/spectator/vitest';
import {
ComponentProjectionStrategy,
PROJECTION_STRATEGY,
@ -73,7 +73,7 @@ describe('RootComponentProjectionStrategy', () => {
baz = 'baz';
}
@Component({
@Component({
template: '',
imports: [],
})
@ -208,9 +208,13 @@ describe('PROJECTION_STRATEGY', () => {
`(
'should successfully map $name to $Strategy.name with $domStrategy.name dom strategy',
({ name, Strategy, domStrategy }) => {
expect(PROJECTION_STRATEGY[name](content, context)).toEqual(
new Strategy(content, CONTEXT_STRATEGY.None(), domStrategy()),
);
const result = PROJECTION_STRATEGY[name](content, context);
const expected = new Strategy(content, CONTEXT_STRATEGY.None(), domStrategy());
expect(result).toBeInstanceOf(Strategy);
expect(result.content).toEqual(expected.content);
expect(result['contextStrategy']).toBeInstanceOf(expected['contextStrategy'].constructor);
expect(result['domStrategy'].position).toBe(expected['domStrategy'].position);
},
);
@ -239,9 +243,14 @@ describe('PROJECTION_STRATEGY', () => {
'should successfully map $name to $Strategy.name with $contextStrategy.name context strategy and $domStrategy.name dom strategy',
({ name, Strategy, domStrategy, contextStrategy }) => {
context = { x: true };
expect(PROJECTION_STRATEGY[name](content, context)).toEqual(
new Strategy(content, contextStrategy(context), domStrategy()),
);
const result = PROJECTION_STRATEGY[name](content, context);
const expected = new Strategy(content, contextStrategy(context), domStrategy());
expect(result).toBeInstanceOf(Strategy);
expect(result.content).toEqual(expected.content);
expect(result['contextStrategy']).toBeInstanceOf(expected['contextStrategy'].constructor);
expect(result['contextStrategy'].context).toEqual(expected['contextStrategy'].context);
expect(result['domStrategy'].position).toBe(expected['domStrategy'].position);
},
);
});

2
npm/ng-packs/packages/core/src/lib/tests/replaceable-route-container.component.spec.ts

@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/vitest';
import { BehaviorSubject } from 'rxjs';
import { ReplaceableRouteContainerComponent } from '../components/replaceable-route-container.component';
import { ReplaceableComponentsService } from '../services/replaceable-components.service';

10
npm/ng-packs/packages/core/src/lib/tests/replaceable-template.directive.spec.ts

@ -1,6 +1,6 @@
import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
import { Router } from '@angular/router';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { BehaviorSubject } from 'rxjs';
import { ReplaceableTemplateDirective } from '../directives/replaceable-template.directive';
import { ReplaceableComponents } from '../models/replaceable-components';
@ -50,8 +50,8 @@ describe('ReplaceableTemplateDirective', () => {
});
describe('without external component', () => {
const twoWayChange = jest.fn(a => a);
const someOutput = jest.fn(a => a);
const twoWayChange = vi.fn(a => a);
const someOutput = vi.fn(a => a);
beforeEach(() => {
spectator = createDirective(
@ -88,8 +88,8 @@ describe('ReplaceableTemplateDirective', () => {
hostProps: {
oneWay: { label: 'Test' },
twoWay: false,
twoWayChange: jest.fn(),
someOutput: jest.fn(),
twoWayChange: vi.fn(),
someOutput: vi.fn(),
},
},
);

20
npm/ng-packs/packages/core/src/lib/tests/rest.service.spec.ts

@ -1,4 +1,4 @@
import { createHttpFactory, HttpMethod, SpectatorHttp, SpyObject } from '@ngneat/spectator/jest';
import { createHttpFactory, HttpMethod, SpectatorHttp, SpyObject } from '@ngneat/spectator/vitest';
import { OAuthService } from 'angular-oauth2-oidc';
import { of, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
@ -74,17 +74,25 @@ describe('HttpClient testing', () => {
spectator.expectOne('bar' + '/test', HttpMethod.GET);
});
test('should complete upon successful request', done => {
const complete = jest.fn(done);
test('should complete upon successful request', async () => {
const request$ = spectator.service.request({ method: HttpMethod.GET, url: '/test' });
spectator.service.request({ method: HttpMethod.GET, url: '/test' }).subscribe({ complete });
// Create a promise that resolves when the observable completes
const completionPromise = new Promise<void>((resolve, reject) => {
request$.subscribe({
complete: () => resolve(),
error: err => reject(err),
});
});
const req = spectator.expectOne(api + '/test', HttpMethod.GET);
spectator.flushAll([req], [{}]);
await completionPromise;
});
test('should handle the error', () => {
const spy = jest.spyOn(httpErrorReporter, 'reportError');
const spy = vi.spyOn(httpErrorReporter, 'reportError');
spectator.service
.request({ method: HttpMethod.GET, url: '/test' }, { observe: Rest.Observe.Events })
@ -102,7 +110,7 @@ describe('HttpClient testing', () => {
});
test('should not handle the error when skipHandleError is true', () => {
const spy = jest.spyOn(httpErrorReporter, 'reportError');
const spy = vi.spyOn(httpErrorReporter, 'reportError');
spectator.service
.request(

4
npm/ng-packs/packages/core/src/lib/tests/route-utils.spec.ts

@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/vitest';
import { RouterOutletComponent } from '../components/router-outlet.component';
import { RoutesService } from '../services/routes.service';
import { findRoute, getRoutePath } from '../utils/route-utils';
@ -23,7 +23,7 @@ describe('Route Utils', () => {
`(
'should find $expected in $count turns when path is $path',
async ({ path, expected, count }) => {
const find = jest.fn(cb => (cb(node) ? node : null));
const find = vi.fn(cb => (cb(node) ? node : null));
const routes = { find } as any as RoutesService;
const route = findRoute(routes, path);
expect(route).toBe(expected);

2
npm/ng-packs/packages/core/src/lib/tests/router-events.service.spec.ts

@ -1,6 +1,6 @@
import { Router, RouterEvent, NavigationStart, ResolveStart, NavigationError, NavigationEnd, ResolveEnd, NavigationCancel } from '@angular/router';
import { Subject } from 'rxjs';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { take } from 'rxjs/operators';
import { NavigationEventKey, RouterEvents } from '../services/router-events.service';

2
npm/ng-packs/packages/core/src/lib/tests/router-outlet.component.spec.ts

@ -1,4 +1,4 @@
import { Spectator, createComponentFactory } from '@ngneat/spectator/jest';
import { Spectator, createComponentFactory } from '@ngneat/spectator/vitest';
import { provideRouter } from '@angular/router';
import { RouterOutletComponent } from '../components/router-outlet.component';

4
npm/ng-packs/packages/core/src/lib/tests/routes.handler.spec.ts

@ -1,7 +1,7 @@
import { Router } from '@angular/router';
import { RoutesHandler } from '../handlers/routes.handler';
import { RoutesService } from '../services/routes.service';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
describe('Routes Handler', () => {
let spectator: SpectatorService<RoutesHandler>;
@ -15,7 +15,7 @@ describe('Routes Handler', () => {
{
provide: RoutesService,
useValue: {
add: jest.fn(),
add: vi.fn(),
},
},
{

30
npm/ng-packs/packages/core/src/lib/tests/routes.service.spec.ts

@ -1,5 +1,5 @@
import { RoutesService } from '../services/routes.service';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { CORE_OPTIONS } from '../tokens/options.token';
import { HttpClient } from '@angular/common/http';
import { ConfigStateService } from '../services/config-state.service';
@ -33,51 +33,51 @@ describe('Routes Service', () => {
{
provide: HttpClient,
useValue: {
get: jest.fn(),
post: jest.fn(),
put: jest.fn(),
delete: jest.fn(),
get: vi.fn(),
post: vi.fn(),
put: vi.fn(),
delete: vi.fn(),
},
},
{
provide: ConfigStateService,
useValue: {
getOne: jest.fn(),
getDeep: jest.fn(),
getDeep$: jest.fn(() => ({ subscribe: jest.fn() })),
createOnUpdateStream: jest.fn(() => ({
subscribe: jest.fn(() => ({ unsubscribe: jest.fn() }))
getOne: vi.fn(),
getDeep: vi.fn(),
getDeep$: vi.fn(() => ({ subscribe: vi.fn() })),
createOnUpdateStream: vi.fn(() => ({
subscribe: vi.fn(() => ({ unsubscribe: vi.fn() }))
})),
},
},
{
provide: AbpApplicationConfigurationService,
useValue: {
get: jest.fn(),
get: vi.fn(),
},
},
{
provide: RestService,
useValue: {
request: jest.fn(),
request: vi.fn(),
},
},
{
provide: EnvironmentService,
useValue: {
getEnvironment: jest.fn(),
getEnvironment: vi.fn(),
},
},
{
provide: HttpErrorReporterService,
useValue: {
reportError: jest.fn(),
reportError: vi.fn(),
},
},
{
provide: ExternalHttpClient,
useValue: {
request: jest.fn(),
request: vi.fn(),
},
},
{

4
npm/ng-packs/packages/core/src/lib/tests/safe-html.pipe.spec.ts

@ -1,4 +1,4 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { SafeHtmlPipe } from '../pipes';
describe('SafeHtmlPipe', () => {
@ -27,7 +27,7 @@ describe('SafeHtmlPipe', () => {
});
it('should sanitize unsafe HTML content', () => {
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
const input = `<script>alert("hello world");</script><p><a href='#' onclick="alert('This is an XSS attack!')">Click here!</a></p>`;
const result = pipe.transform(input);
expect(result).toBe(`<p><a href="#">Click here!</a></p>`);

118
npm/ng-packs/packages/core/src/lib/tests/show-password-directive.spec.ts

@ -1,55 +1,63 @@
import { Component, DebugElement } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { ShowPasswordDirective } from '../directives';
import { By } from '@angular/platform-browser';
@Component({
standalone:true,
template: `
<input [abpShowPassword]="true">
<input [abpShowPassword]="false">
<input />
<input [abpShowPassword]="showPassword" />`,
imports:[ShowPasswordDirective]
})
class TestComponent {
showPassword = false
}
describe('ShowPasswordDirective',()=>{
let fixture: ComponentFixture<TestComponent>;;
let des : DebugElement[];
let desAll : DebugElement[];
let bareInput;
beforeEach(()=>{
fixture = TestBed.configureTestingModule({
imports: [ TestComponent ]
}).createComponent(TestComponent)
fixture.detectChanges();
des = fixture.debugElement.queryAll(By.directive(ShowPasswordDirective));
desAll = fixture.debugElement.queryAll(By.all());
bareInput = fixture.debugElement.query(By.css('input:not([abpShowPassword])'));
})
it('should have three input has ShowPasswordDirective elements', () => {
expect(des.length).toBe(3);
});
test.each([[0,'text'],[1,'password'],[2,'text'],[3,'password']])('%p. input type must be %p)', (index,inpType) => {
const inputType = desAll[index].nativeElement.type;
expect(inputType).toBe(inpType);
});
it('should have three input has ShowPasswordDirective elements', () => {
const input = des[2].nativeElement
expect(input.type).toBe('password')
fixture.componentInstance.showPassword = true
fixture.detectChanges()
expect(input.type).toBe('text')
});
});
import { Component, DebugElement, ChangeDetectorRef } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ShowPasswordDirective } from '../directives';
@Component({
template: ` <input [abpShowPassword]="true" />
<input [abpShowPassword]="false" />
<input />
<input [abpShowPassword]="showPassword" />`,
imports: [ShowPasswordDirective],
})
class TestComponent {
showPassword = false;
}
describe('ShowPasswordDirective', () => {
let fixture: ComponentFixture<TestComponent>;
let des: DebugElement[];
let desAll: DebugElement[];
let bareInput;
beforeEach(() => {
fixture = TestBed.configureTestingModule({
imports: [TestComponent],
}).createComponent(TestComponent);
fixture.detectChanges();
des = fixture.debugElement.queryAll(By.directive(ShowPasswordDirective));
desAll = fixture.debugElement.queryAll(By.all());
bareInput = fixture.debugElement.query(By.css('input:not([abpShowPassword])'));
});
it('should have three input has ShowPasswordDirective elements', () => {
expect(des.length).toBe(3);
});
test.each([
[0, 'text'],
[1, 'password'],
[2, 'text'],
[3, 'password'],
])('%p. input type must be %p)', (index, inpType) => {
const inputType = desAll[index].nativeElement.type;
expect(inputType).toBe(inpType);
});
it('should toggle input type when showPassword changes', () => {
const input = des[2].nativeElement;
expect(input.type).toBe('password');
fixture.componentInstance.showPassword = true;
const cdr = fixture.componentRef.injector.get(ChangeDetectorRef);
cdr.markForCheck();
cdr.detectChanges();
expect(input.type).toBe('text');
});
});

2
npm/ng-packs/packages/core/src/lib/tests/sort.pipe.spec.ts

@ -1,4 +1,4 @@
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/jest';
import { createServiceFactory, SpectatorService } from '@ngneat/spectator/vitest';
import { SortPipe } from '../pipes/sort.pipe';
describe('SortPipe', () => {

9
npm/ng-packs/packages/core/src/lib/tests/stop-propagation.directive.spec.ts

@ -1,12 +1,12 @@
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/jest';
import { createDirectiveFactory, SpectatorDirective } from '@ngneat/spectator/vitest';
import { StopPropagationDirective } from '../directives/stop-propagation.directive';
describe('StopPropagationDirective', () => {
let spectator: SpectatorDirective<StopPropagationDirective>;
let directive: StopPropagationDirective;
let link: HTMLAnchorElement;
const childClickEventFn = jest.fn(() => null);
const parentClickEventFn = jest.fn(() => null);
const childClickEventFn = vi.fn(() => null);
const parentClickEventFn = vi.fn(() => null);
const createDirective = createDirectiveFactory({
directive: StopPropagationDirective,
});
@ -28,12 +28,11 @@ describe('StopPropagationDirective', () => {
expect(directive).toBeTruthy();
});
test('should not call click event of parent when child element is clicked', done => {
test('should not call click event of parent when child element is clicked', () => {
spectator.setHostInput({ parentClickEventFn, childClickEventFn });
spectator.click('a');
spectator.detectChanges();
expect(childClickEventFn).toHaveBeenCalled();
expect(parentClickEventFn).not.toHaveBeenCalled();
done();
});
});

6
npm/ng-packs/packages/core/src/lib/tests/subscription.service.spec.ts

@ -14,8 +14,8 @@ describe('SubscriptionService', () => {
describe('#addOne', () => {
it('should subscribe to given observable with next and error functions and return the Subscription instance', () => {
const next = jest.fn();
const error = jest.fn();
const next = vi.fn();
const error = vi.fn();
const subscription = service.addOne(of(null), next, error);
expect(subscription).toBeInstanceOf(Subscription);
expect(next).toHaveBeenCalledWith(null);
@ -24,7 +24,7 @@ describe('SubscriptionService', () => {
});
it('should subscribe to given observable with observer and return the Subscription instance', () => {
const observer = { next: jest.fn(), complete: jest.fn() };
const observer = { next: vi.fn(), complete: vi.fn() };
const subscription = service.addOne(of(null), observer);
expect(subscription).toBeInstanceOf(Subscription);
expect(observer.next).toHaveBeenCalledWith(null);

10
npm/ng-packs/packages/core/src/test-setup.ts

@ -1,7 +1,11 @@
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv();
import 'zone.js';
import 'zone.js/testing';
import { getTestBed } from '@angular/core/testing';
import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing';
// Initialize Angular testing environment
getTestBed().initTestEnvironment(BrowserTestingModule, platformBrowserTesting());
// Mock window.location for test environment
Object.defineProperty(window, 'location', {
value: {
href: 'http://localhost:4200',

19
npm/ng-packs/packages/core/tsconfig.lib.json

@ -10,6 +10,23 @@
"lib": ["dom", "es2020"],
"useDefineForClassFields": false
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"],
"exclude": [
"src/test-setup.ts",
"**/*.spec.ts",
"jest.config.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/test-setup.ts"
],
"include": ["**/*.ts"]
}

22
npm/ng-packs/packages/core/tsconfig.spec.json

@ -2,10 +2,22 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.ts"]
"include": [
"vite.config.ts",
"vitest.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

22
npm/ng-packs/packages/core/vitest.config.mts

@ -0,0 +1,22 @@
import { defineConfig } from 'vitest/config';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/core',
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
test: {
name: 'core',
watch: false,
globals: true,
environment: 'jsdom',
setupFiles: ['src/test-setup.ts'],
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/packages/core',
provider: 'v8' as const,
},
},
}));

2
npm/ng-packs/packages/feature-management/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts"],

4
npm/ng-packs/packages/feature-management/jest.config.ts

@ -1,4 +1,8 @@
/* eslint-disable */
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default {
displayName: 'feature-management',
preset: '../../jest.preset.js',

14
npm/ng-packs/packages/feature-management/project.json

@ -23,16 +23,16 @@
},
"defaultConfiguration": "production"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/feature-management"],
"options": {
"jestConfig": "packages/feature-management/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../coverage/packages/feature-management"
}
}
}
}

19
npm/ng-packs/packages/feature-management/tsconfig.lib.json

@ -10,6 +10,23 @@
"lib": ["dom", "es2020"],
"useDefineForClassFields": false
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"],
"exclude": [
"src/test-setup.ts",
"**/*.spec.ts",
"jest.config.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/test-setup.ts"
],
"include": ["**/*.ts"]
}

22
npm/ng-packs/packages/feature-management/tsconfig.spec.json

@ -2,10 +2,22 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

21
npm/ng-packs/packages/feature-management/vitest.config.mts

@ -0,0 +1,21 @@
import { defineConfig } from 'vitest/config';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/feature-management',
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
test: {
name: 'feature-management',
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/packages/feature-management',
provider: 'v8' as const,
},
},
}));

2
npm/ng-packs/packages/generators/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],

4
npm/ng-packs/packages/generators/jest.config.ts

@ -1,4 +1,8 @@
/* eslint-disable */
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default {
displayName: 'generators',
preset: '../../jest.preset.js',

6
npm/ng-packs/packages/generators/project.json

@ -46,10 +46,10 @@
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"jestConfig": "packages/generators/jest.config.ts"
"reportsDirectory": "../../coverage/packages/generators"
}
}
}

6
npm/ng-packs/packages/generators/src/generators/change-theme/generator.spec.ts

@ -1,11 +1,11 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Tree, readProjectConfiguration } from '@nx/devkit';
import { Tree } from '@nx/devkit';
import { changeThemeGenerator } from './generator';
import { ChangeThemeGeneratorSchema } from './schema';
jest.mock('@nx/devkit/ngcli-adapter', () => ({
wrapAngularDevkitSchematic: jest.fn(() => jest.fn()),
vi.mock('@nx/devkit/ngcli-adapter', () => ({
wrapAngularDevkitSchematic: vi.fn(() => vi.fn()),
}));
describe('change-theme generator', () => {

16
npm/ng-packs/packages/generators/tsconfig.lib.json

@ -6,5 +6,19 @@
"types": ["node"]
},
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
"exclude": [
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx"
]
}

19
npm/ng-packs/packages/generators/tsconfig.spec.json

@ -2,8 +2,21 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
]
}

21
npm/ng-packs/packages/generators/vitest.config.mts

@ -0,0 +1,21 @@
import { defineConfig } from 'vitest/config';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
export default defineConfig(() => ({
root: __dirname,
cacheDir: '../../node_modules/.vite/packages/generators',
plugins: [nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
test: {
name: 'generators',
watch: false,
globals: true,
environment: 'jsdom',
include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
reporters: ['default'],
coverage: {
reportsDirectory: '../../coverage/packages/generators',
provider: 'v8' as const,
},
},
}));

2
npm/ng-packs/packages/identity/.eslintrc.json

@ -1,6 +1,6 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"ignorePatterns": ["!**/*", "**/vitest.config.*.timestamp*"],
"overrides": [
{
"files": ["*.ts"],

4
npm/ng-packs/packages/identity/jest.config.ts

@ -1,4 +1,8 @@
/* eslint-disable */
/**
* @deprecated use vitest instead of jest
* @see https://vitest.dev/guide/migration.html#jest
*/
export default {
displayName: 'identity',
preset: '../../jest.preset.js',

14
npm/ng-packs/packages/identity/project.json

@ -23,16 +23,16 @@
},
"defaultConfiguration": "production"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/packages/identity"],
"options": {
"jestConfig": "packages/identity/jest.config.ts"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": ["{options.outputFile}"]
},
"test": {
"executor": "@nx/vitest:test",
"outputs": ["{options.reportsDirectory}"],
"options": {
"reportsDirectory": "../../coverage/packages/identity"
}
}
}
}

19
npm/ng-packs/packages/identity/tsconfig.lib.json

@ -10,6 +10,23 @@
"lib": ["dom", "es2020"],
"useDefineForClassFields": false
},
"exclude": ["src/test-setup.ts", "**/*.spec.ts", "jest.config.ts"],
"exclude": [
"src/test-setup.ts",
"**/*.spec.ts",
"jest.config.ts",
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/test-setup.ts"
],
"include": ["**/*.ts"]
}

22
npm/ng-packs/packages/identity/tsconfig.spec.json

@ -2,10 +2,22 @@
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"],
"esModuleInterop": true
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
},
"files": ["src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts", "jest.config.ts"]
"include": [
"vite.config.ts",
"vite.config.mts",
"vitest.config.ts",
"vitest.config.mts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.test.tsx",
"src/**/*.spec.tsx",
"src/**/*.test.js",
"src/**/*.spec.js",
"src/**/*.test.jsx",
"src/**/*.spec.jsx",
"src/**/*.d.ts"
],
"files": ["src/test-setup.ts"]
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save