@nocios/crudify-components 2.0.61 → 2.0.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/api-jcCTCqPD.d.mts +61 -0
- package/dist/api-jcCTCqPD.d.ts +61 -0
- package/dist/chunk-4I767MRM.mjs +142 -0
- package/dist/chunk-5V5ILPP3.js +1 -0
- package/dist/chunk-BJEDX2HU.js +142 -0
- package/dist/chunk-GZOB4JDB.js +1 -0
- package/dist/chunk-ODKXUEH5.js +1 -0
- package/dist/chunk-U335FNUD.mjs +1 -0
- package/dist/chunk-YRU7AXYV.mjs +1 -0
- package/dist/chunk-Z75DRSTN.mjs +1 -0
- package/dist/{errorTranslation-CF-5JClP.d.ts → errorTranslation-BdqG-dXD.d.ts} +97 -26
- package/dist/{errorTranslation-BcX8AaK7.d.mts → errorTranslation-BxJmBGx0.d.mts} +97 -26
- package/dist/hooks.d.mts +3 -4
- package/dist/hooks.d.ts +3 -4
- package/dist/hooks.js +1 -1
- package/dist/hooks.mjs +1 -1
- package/dist/{index-D06kTP0C.d.mts → index-Cx9P3ZCG.d.mts} +225 -139
- package/dist/{index-DEDnmsdO.d.ts → index-rHtWMls-.d.ts} +225 -139
- package/dist/index.d.mts +508 -213
- package/dist/index.d.ts +508 -213
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/dist/public-policies.d.mts +7 -0
- package/dist/public-policies.d.ts +7 -0
- package/dist/public-policies.js +1 -0
- package/dist/public-policies.mjs +1 -0
- package/dist/utils.d.mts +94 -26
- package/dist/utils.d.ts +94 -26
- package/dist/utils.js +1 -1
- package/dist/utils.mjs +1 -1
- package/package.json +44 -42
- package/.github/workflows/ci.yml +0 -70
- package/.husky/pre-commit +0 -26
- package/.husky/pre-push +0 -30
- package/.nvmrc +0 -1
- package/.prettierignore +0 -18
- package/.prettierrc +0 -9
- package/README_DEPTH.md +0 -1237
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/coverage-final.json +0 -120
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -686
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -686
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -22388
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/dist/CrudiaMarkdownField-CkiBwG-U.d.ts +0 -343
- package/dist/CrudiaMarkdownField-D-DqiXMQ.d.mts +0 -343
- package/dist/GlobalNotificationProvider-CdwdNv_8.d.mts +0 -96
- package/dist/GlobalNotificationProvider-CdwdNv_8.d.ts +0 -96
- package/dist/chunk-2WAUZ6KI.js +0 -1
- package/dist/chunk-3IGZNZCT.mjs +0 -1
- package/dist/chunk-43L2PP77.mjs +0 -1
- package/dist/chunk-6VS5OT3A.mjs +0 -1
- package/dist/chunk-BWJTTMKS.js +0 -1
- package/dist/chunk-EMPPCCVU.js +0 -1
- package/dist/chunk-J43UPGBE.js +0 -1
- package/dist/chunk-K6ZRXOJ7.mjs +0 -1
- package/dist/chunk-RYQQZTEP.js +0 -1
- package/dist/chunk-VTMSOK4V.mjs +0 -1
- package/dist/components.d.mts +0 -24
- package/dist/components.d.ts +0 -24
- package/dist/components.js +0 -1
- package/dist/components.mjs +0 -1
- package/dist/tenantConfig-CYnS9TPV.d.mts +0 -318
- package/dist/tenantConfig-CYnS9TPV.d.ts +0 -318
- package/eslint.config.mjs +0 -140
- package/scripts/bump-version.cjs +0 -23
- package/sonar-project.properties +0 -23
- package/tests/helpers/testUtils.tsx +0 -89
- package/tests/hooks/useSession/testUtils.tsx +0 -212
- package/tests/setup.ts +0 -139
- package/tests/vitest.d.ts +0 -1
- package/vitest.config.ts +0 -39
package/eslint.config.mjs
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import tseslint from '@typescript-eslint/eslint-plugin';
|
|
2
|
-
import tsparser from '@typescript-eslint/parser';
|
|
3
|
-
import react from 'eslint-plugin-react';
|
|
4
|
-
import reactHooks from 'eslint-plugin-react-hooks';
|
|
5
|
-
|
|
6
|
-
export default [
|
|
7
|
-
{
|
|
8
|
-
ignores: ['dist/**', 'node_modules/**', 'coverage/**'],
|
|
9
|
-
},
|
|
10
|
-
// Configuracion para archivos TypeScript (.ts)
|
|
11
|
-
{
|
|
12
|
-
files: ['src/**/*.ts'],
|
|
13
|
-
languageOptions: {
|
|
14
|
-
parser: tsparser,
|
|
15
|
-
parserOptions: {
|
|
16
|
-
ecmaVersion: 'latest',
|
|
17
|
-
sourceType: 'module',
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
plugins: {
|
|
21
|
-
'@typescript-eslint': tseslint,
|
|
22
|
-
},
|
|
23
|
-
rules: {
|
|
24
|
-
...tseslint.configs.recommended.rules,
|
|
25
|
-
'@typescript-eslint/no-unused-vars': [
|
|
26
|
-
'error',
|
|
27
|
-
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_' },
|
|
28
|
-
],
|
|
29
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
|
30
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
31
|
-
'@typescript-eslint/no-non-null-assertion': 'warn',
|
|
32
|
-
'curly': ['error', 'all'],
|
|
33
|
-
'brace-style': ['error', '1tbs', { allowSingleLine: false }],
|
|
34
|
-
'no-console': 'warn',
|
|
35
|
-
'no-restricted-syntax': [
|
|
36
|
-
'error',
|
|
37
|
-
{
|
|
38
|
-
selector: 'ExportDefaultDeclaration',
|
|
39
|
-
message: 'Prefer named exports instead of default exports',
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
// Configuracion para archivos React (.tsx)
|
|
45
|
-
{
|
|
46
|
-
files: ['src/**/*.tsx'],
|
|
47
|
-
languageOptions: {
|
|
48
|
-
parser: tsparser,
|
|
49
|
-
parserOptions: {
|
|
50
|
-
ecmaVersion: 'latest',
|
|
51
|
-
sourceType: 'module',
|
|
52
|
-
ecmaFeatures: {
|
|
53
|
-
jsx: true,
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
plugins: {
|
|
58
|
-
'@typescript-eslint': tseslint,
|
|
59
|
-
react: react,
|
|
60
|
-
'react-hooks': reactHooks,
|
|
61
|
-
},
|
|
62
|
-
settings: {
|
|
63
|
-
react: {
|
|
64
|
-
version: 'detect',
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
rules: {
|
|
68
|
-
...tseslint.configs.recommended.rules,
|
|
69
|
-
...react.configs.recommended.rules,
|
|
70
|
-
...reactHooks.configs.recommended.rules,
|
|
71
|
-
'@typescript-eslint/no-unused-vars': [
|
|
72
|
-
'error',
|
|
73
|
-
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_' },
|
|
74
|
-
],
|
|
75
|
-
'@typescript-eslint/no-explicit-any': 'warn',
|
|
76
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
77
|
-
'@typescript-eslint/no-non-null-assertion': 'warn',
|
|
78
|
-
'curly': ['error', 'all'],
|
|
79
|
-
'brace-style': ['error', '1tbs', { allowSingleLine: false }],
|
|
80
|
-
'no-console': 'warn',
|
|
81
|
-
// React 17+ no requiere importar React
|
|
82
|
-
'react/react-in-jsx-scope': 'off',
|
|
83
|
-
// Props spreading es comun en componentes UI
|
|
84
|
-
'react/jsx-props-no-spreading': 'off',
|
|
85
|
-
// Usamos TypeScript para validar props, no necesitamos prop-types
|
|
86
|
-
'react/prop-types': 'off',
|
|
87
|
-
// Para componentes, permitir default exports (warn en lugar de error)
|
|
88
|
-
'no-restricted-syntax': [
|
|
89
|
-
'warn',
|
|
90
|
-
{
|
|
91
|
-
selector: 'ExportDefaultDeclaration',
|
|
92
|
-
message: 'Consider using named exports instead of default exports',
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
// Configuracion mas permisiva para archivos de test
|
|
98
|
-
{
|
|
99
|
-
files: [
|
|
100
|
-
'src/**/*.test.ts',
|
|
101
|
-
'src/**/*.test.tsx',
|
|
102
|
-
'src/**/*.spec.ts',
|
|
103
|
-
'src/**/*.spec.tsx',
|
|
104
|
-
'src/__tests__/**/*.ts',
|
|
105
|
-
'src/__tests__/**/*.tsx',
|
|
106
|
-
],
|
|
107
|
-
rules: {
|
|
108
|
-
'@typescript-eslint/no-unused-vars': 'warn',
|
|
109
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
110
|
-
'@typescript-eslint/no-unsafe-function-type': 'off',
|
|
111
|
-
'@typescript-eslint/no-non-null-assertion': 'off',
|
|
112
|
-
'@typescript-eslint/ban-ts-comment': 'off',
|
|
113
|
-
'no-console': 'off',
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
// Configuracion para hooks .ts (agregar react-hooks y permitir default exports con warning)
|
|
117
|
-
{
|
|
118
|
-
files: ['src/**/hooks/**/*.ts', 'src/hooks/**/*.ts'],
|
|
119
|
-
plugins: {
|
|
120
|
-
'react-hooks': reactHooks,
|
|
121
|
-
},
|
|
122
|
-
rules: {
|
|
123
|
-
...reactHooks.configs.recommended.rules,
|
|
124
|
-
'no-restricted-syntax': [
|
|
125
|
-
'warn',
|
|
126
|
-
{
|
|
127
|
-
selector: 'ExportDefaultDeclaration',
|
|
128
|
-
message: 'Consider using named exports instead of default exports',
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
// Configuracion para archivos de declaracion (.d.ts) - permiten default exports para CSS modules
|
|
134
|
-
{
|
|
135
|
-
files: ['src/**/*.d.ts'],
|
|
136
|
-
rules: {
|
|
137
|
-
'no-restricted-syntax': 'off',
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
];
|
package/scripts/bump-version.cjs
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Auto-increment patch version in package.json
|
|
3
|
-
*
|
|
4
|
-
* This script increments the patch version (e.g., 2.0.44 -> 2.0.45)
|
|
5
|
-
* and writes it back to package.json
|
|
6
|
-
*/
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
|
|
10
|
-
const packagePath = path.join(__dirname, '../package.json');
|
|
11
|
-
const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
|
12
|
-
|
|
13
|
-
// Parse current version
|
|
14
|
-
const [major, minor, patch] = pkg.version.split('.').map(Number);
|
|
15
|
-
|
|
16
|
-
// Increment patch version
|
|
17
|
-
const newVersion = `${major}.${minor}.${patch + 1}`;
|
|
18
|
-
|
|
19
|
-
// Update package.json
|
|
20
|
-
pkg.version = newVersion;
|
|
21
|
-
fs.writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n');
|
|
22
|
-
|
|
23
|
-
console.log(`✓ Version bumped: ${major}.${minor}.${patch} → ${newVersion}`);
|
package/sonar-project.properties
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Identificacion del proyecto
|
|
2
|
-
sonar.projectKey=nocios_crudify-components
|
|
3
|
-
sonar.projectName=crudify-components
|
|
4
|
-
sonar.projectVersion=2.0.44
|
|
5
|
-
|
|
6
|
-
# Configuracion de fuentes
|
|
7
|
-
sonar.sources=src
|
|
8
|
-
sonar.tests=tests
|
|
9
|
-
sonar.sourceEncoding=UTF-8
|
|
10
|
-
|
|
11
|
-
# Reporte de cobertura
|
|
12
|
-
sonar.typescript.lcov.reportPaths=coverage/lcov.info
|
|
13
|
-
sonar.javascript.lcov.reportPaths=coverage/lcov.info
|
|
14
|
-
|
|
15
|
-
# Exclusiones
|
|
16
|
-
sonar.exclusions=**/node_modules/**,**/dist/**,**/*.test.ts,**/*.spec.ts,**/*.test.tsx,**/*.spec.tsx,**/example/**
|
|
17
|
-
sonar.coverage.exclusions=**/index.ts,**/types.ts,**/types.d.ts,**/*.d.ts
|
|
18
|
-
|
|
19
|
-
# Inclusiones de tests
|
|
20
|
-
sonar.test.inclusions=tests/**/*.test.ts,tests/**/*.spec.ts,tests/**/*.test.tsx,tests/**/*.spec.tsx
|
|
21
|
-
|
|
22
|
-
# Quality Gate
|
|
23
|
-
sonar.qualitygate.wait=true
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Utilities
|
|
3
|
-
* Common utilities and helpers for testing
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { render, RenderOptions, RenderResult } from '@testing-library/react';
|
|
7
|
-
import { ReactElement, ReactNode } from 'react';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Custom render function with providers
|
|
11
|
-
*/
|
|
12
|
-
export function renderWithProviders(ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>): RenderResult {
|
|
13
|
-
function Wrapper({ children }: { children: ReactNode }) {
|
|
14
|
-
return <>{children}</>;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return render(ui, { wrapper: Wrapper, ...options });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Wait for a condition to be true
|
|
22
|
-
*/
|
|
23
|
-
export async function waitForCondition(condition: () => boolean, timeout = 5000): Promise<void> {
|
|
24
|
-
const startTime = Date.now();
|
|
25
|
-
while (!condition()) {
|
|
26
|
-
if (Date.now() - startTime > timeout) {
|
|
27
|
-
throw new Error('Timeout waiting for condition');
|
|
28
|
-
}
|
|
29
|
-
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Mock localStorage
|
|
35
|
-
*/
|
|
36
|
-
export function mockLocalStorage() {
|
|
37
|
-
const store: Record<string, string> = {};
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
getItem: (key: string) => store[key] || null,
|
|
41
|
-
setItem: (key: string, value: string) => {
|
|
42
|
-
store[key] = value;
|
|
43
|
-
},
|
|
44
|
-
removeItem: (key: string) => {
|
|
45
|
-
delete store[key];
|
|
46
|
-
},
|
|
47
|
-
clear: () => {
|
|
48
|
-
Object.keys(store).forEach((key) => delete store[key]);
|
|
49
|
-
},
|
|
50
|
-
get length() {
|
|
51
|
-
return Object.keys(store).length;
|
|
52
|
-
},
|
|
53
|
-
key: (index: number) => Object.keys(store)[index] || null,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Create mock JWT token
|
|
59
|
-
*/
|
|
60
|
-
export function createMockJWT(payload: Record<string, any>, exp?: number): string {
|
|
61
|
-
const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' }));
|
|
62
|
-
const body = btoa(
|
|
63
|
-
JSON.stringify({
|
|
64
|
-
...payload,
|
|
65
|
-
exp: exp || Math.floor(Date.now() / 1000) + 3600,
|
|
66
|
-
iat: Math.floor(Date.now() / 1000),
|
|
67
|
-
})
|
|
68
|
-
);
|
|
69
|
-
const signature = btoa('mock-signature');
|
|
70
|
-
return `${header}.${body}.${signature}`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Sleep utility for tests
|
|
75
|
-
*/
|
|
76
|
-
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Mock fetch response
|
|
80
|
-
*/
|
|
81
|
-
export function mockFetchResponse(data: any, status = 200) {
|
|
82
|
-
return Promise.resolve({
|
|
83
|
-
ok: status >= 200 && status < 300,
|
|
84
|
-
status,
|
|
85
|
-
json: () => Promise.resolve(data),
|
|
86
|
-
text: () => Promise.resolve(JSON.stringify(data)),
|
|
87
|
-
headers: new Headers(),
|
|
88
|
-
} as Response);
|
|
89
|
-
}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utilidades compartidas para tests de useSession
|
|
3
|
-
* Incluye mocks, factories y wrappers
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import React from 'react';
|
|
7
|
-
import { vi } from 'vitest';
|
|
8
|
-
import { TokenData } from '../../../src/utils/tokenStorage';
|
|
9
|
-
|
|
10
|
-
// =============================
|
|
11
|
-
// MOCK FACTORIES
|
|
12
|
-
// =============================
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Crea datos de token mock para tests
|
|
16
|
-
*/
|
|
17
|
-
export function createMockTokens(overrides?: Partial<TokenData>): TokenData {
|
|
18
|
-
const now = Date.now();
|
|
19
|
-
return {
|
|
20
|
-
accessToken: 'mock-access-token',
|
|
21
|
-
refreshToken: 'mock-refresh-token',
|
|
22
|
-
expiresAt: now + 15 * 60 * 1000, // 15 minutos
|
|
23
|
-
refreshExpiresAt: now + 7 * 24 * 60 * 60 * 1000, // 7 días
|
|
24
|
-
...overrides,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Crea tokens expirados para tests
|
|
30
|
-
*/
|
|
31
|
-
export function createExpiredTokens(): TokenData {
|
|
32
|
-
const now = Date.now();
|
|
33
|
-
return {
|
|
34
|
-
accessToken: 'expired-access-token',
|
|
35
|
-
refreshToken: 'expired-refresh-token',
|
|
36
|
-
expiresAt: now - 1000, // Ya expiró
|
|
37
|
-
refreshExpiresAt: now + 7 * 24 * 60 * 60 * 1000,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Crea tokens que expiran pronto para tests
|
|
43
|
-
*/
|
|
44
|
-
export function createExpiringSoonTokens(): TokenData {
|
|
45
|
-
const now = Date.now();
|
|
46
|
-
return {
|
|
47
|
-
accessToken: 'expiring-access-token',
|
|
48
|
-
refreshToken: 'expiring-refresh-token',
|
|
49
|
-
expiresAt: now + 2 * 60 * 1000, // 2 minutos (menos de 5)
|
|
50
|
-
refreshExpiresAt: now + 7 * 24 * 60 * 60 * 1000,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// =============================
|
|
55
|
-
// MOCK SESSION MANAGER
|
|
56
|
-
// =============================
|
|
57
|
-
|
|
58
|
-
export function createMockSessionManager() {
|
|
59
|
-
return {
|
|
60
|
-
getInstance: vi.fn(),
|
|
61
|
-
initialize: vi.fn().mockResolvedValue(undefined),
|
|
62
|
-
login: vi.fn().mockResolvedValue({ success: true, tokens: createMockTokens() }),
|
|
63
|
-
logout: vi.fn().mockResolvedValue(undefined),
|
|
64
|
-
refreshTokens: vi.fn().mockResolvedValue(true),
|
|
65
|
-
refreshTokensSilent: vi.fn().mockResolvedValue(true),
|
|
66
|
-
getTokenInfo: vi.fn().mockResolvedValue({
|
|
67
|
-
crudifyTokens: {
|
|
68
|
-
accessToken: 'mock-access-token',
|
|
69
|
-
refreshToken: 'mock-refresh-token',
|
|
70
|
-
expiresAt: Date.now() + 15 * 60 * 1000,
|
|
71
|
-
refreshExpiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
|
|
72
|
-
expiresIn: 15 * 60 * 1000,
|
|
73
|
-
},
|
|
74
|
-
}),
|
|
75
|
-
isAuthenticated: vi.fn().mockResolvedValue(true),
|
|
76
|
-
isRefreshing: vi.fn().mockReturnValue(false),
|
|
77
|
-
updateLastActivity: vi.fn(),
|
|
78
|
-
setupResponseInterceptor: vi.fn(),
|
|
79
|
-
getTimeSinceLastActivity: vi.fn().mockReturnValue(0),
|
|
80
|
-
clearSession: vi.fn().mockResolvedValue(undefined),
|
|
81
|
-
// ✅ FASE 5: Nuevo método para verificar sesión activa
|
|
82
|
-
getIsSessionActive: vi.fn().mockReturnValue(true),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// =============================
|
|
87
|
-
// MOCK TOKEN STORAGE
|
|
88
|
-
// =============================
|
|
89
|
-
|
|
90
|
-
export function createMockTokenStorage() {
|
|
91
|
-
const subscribers: Array<(tokens: TokenData | null, eventType: string, hadPreviousTokens: boolean) => void> = [];
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
saveTokens: vi.fn().mockResolvedValue(undefined),
|
|
95
|
-
getTokens: vi.fn().mockResolvedValue(createMockTokens()),
|
|
96
|
-
clearTokens: vi.fn().mockResolvedValue(undefined),
|
|
97
|
-
hasValidTokens: vi.fn().mockResolvedValue(true),
|
|
98
|
-
getExpirationInfo: vi.fn().mockResolvedValue({
|
|
99
|
-
expiresAt: Date.now() + 15 * 60 * 1000,
|
|
100
|
-
refreshExpiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
|
|
101
|
-
}),
|
|
102
|
-
subscribeToChanges: vi.fn((callback) => {
|
|
103
|
-
subscribers.push(callback);
|
|
104
|
-
return () => {
|
|
105
|
-
const index = subscribers.indexOf(callback);
|
|
106
|
-
if (index > -1) {
|
|
107
|
-
subscribers.splice(index, 1);
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
}),
|
|
111
|
-
SYNC_EVENTS: {
|
|
112
|
-
TOKENS_CLEARED: 'TOKENS_CLEARED',
|
|
113
|
-
TOKENS_UPDATED: 'TOKENS_UPDATED',
|
|
114
|
-
},
|
|
115
|
-
// Helper para simular eventos en tests
|
|
116
|
-
_emitEvent: (tokens: TokenData | null, eventType: string, hadPreviousTokens: boolean) => {
|
|
117
|
-
subscribers.forEach((cb) => cb(tokens, eventType, hadPreviousTokens));
|
|
118
|
-
},
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// =============================
|
|
123
|
-
// MOCK AUTH EVENT BUS
|
|
124
|
-
// =============================
|
|
125
|
-
|
|
126
|
-
export function createMockAuthEventBus() {
|
|
127
|
-
const subscribers: Array<(event: { type: string; details?: Record<string, unknown> }) => void> = [];
|
|
128
|
-
|
|
129
|
-
return {
|
|
130
|
-
subscribe: vi.fn((callback) => {
|
|
131
|
-
subscribers.push(callback);
|
|
132
|
-
return () => {
|
|
133
|
-
const index = subscribers.indexOf(callback);
|
|
134
|
-
if (index > -1) {
|
|
135
|
-
subscribers.splice(index, 1);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
}),
|
|
139
|
-
emit: vi.fn(),
|
|
140
|
-
// Helper para simular eventos en tests
|
|
141
|
-
_emitEvent: (type: string, details?: Record<string, unknown>) => {
|
|
142
|
-
subscribers.forEach((cb) => cb({ type, details }));
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// =============================
|
|
148
|
-
// MOCK NAVIGATION TRACKER
|
|
149
|
-
// =============================
|
|
150
|
-
|
|
151
|
-
export function createMockNavigationTracker() {
|
|
152
|
-
const subscribers: Array<() => void> = [];
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
getInstance: vi.fn().mockReturnThis(),
|
|
156
|
-
subscribe: vi.fn((callback) => {
|
|
157
|
-
subscribers.push(callback);
|
|
158
|
-
return () => {
|
|
159
|
-
const index = subscribers.indexOf(callback);
|
|
160
|
-
if (index > -1) {
|
|
161
|
-
subscribers.splice(index, 1);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
}),
|
|
165
|
-
// Helper para simular navegación en tests
|
|
166
|
-
_emitNavigation: () => {
|
|
167
|
-
subscribers.forEach((cb) => cb());
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// =============================
|
|
173
|
-
// REACT WRAPPER
|
|
174
|
-
// =============================
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Wrapper para tests de hooks con React
|
|
178
|
-
*/
|
|
179
|
-
export function createWrapper() {
|
|
180
|
-
return function Wrapper({ children }: { children: React.ReactNode }) {
|
|
181
|
-
return <>{children}</>;
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// =============================
|
|
186
|
-
// WAIT UTILITIES
|
|
187
|
-
// =============================
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Espera un tiempo específico
|
|
191
|
-
*/
|
|
192
|
-
export function wait(ms: number): Promise<void> {
|
|
193
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Espera hasta que una condición sea verdadera
|
|
198
|
-
*/
|
|
199
|
-
export async function waitFor(
|
|
200
|
-
condition: () => boolean,
|
|
201
|
-
options: { timeout?: number; interval?: number } = {}
|
|
202
|
-
): Promise<void> {
|
|
203
|
-
const { timeout = 5000, interval = 50 } = options;
|
|
204
|
-
const startTime = Date.now();
|
|
205
|
-
|
|
206
|
-
while (!condition()) {
|
|
207
|
-
if (Date.now() - startTime > timeout) {
|
|
208
|
-
throw new Error('waitFor timeout');
|
|
209
|
-
}
|
|
210
|
-
await wait(interval);
|
|
211
|
-
}
|
|
212
|
-
}
|
package/tests/setup.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test Setup File
|
|
3
|
-
* Configures the testing environment with all necessary mocks and utilities
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { afterEach, beforeEach, vi } from 'vitest';
|
|
7
|
-
import { cleanup } from '@testing-library/react';
|
|
8
|
-
import '@testing-library/jest-dom/vitest';
|
|
9
|
-
|
|
10
|
-
// Mock window.history para tests
|
|
11
|
-
const originalPushState = window.history.pushState;
|
|
12
|
-
const originalReplaceState = window.history.replaceState;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
// Restaurar métodos originales antes de cada test
|
|
16
|
-
window.history.pushState = originalPushState;
|
|
17
|
-
window.history.replaceState = originalReplaceState;
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
// Cleanup after each test case
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
cleanup();
|
|
23
|
-
localStorage.clear();
|
|
24
|
-
sessionStorage.clear();
|
|
25
|
-
vi.clearAllMocks();
|
|
26
|
-
|
|
27
|
-
// Cleanup después de cada test
|
|
28
|
-
window.history.pushState = originalPushState;
|
|
29
|
-
window.history.replaceState = originalReplaceState;
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// Mock window.matchMedia
|
|
33
|
-
Object.defineProperty(window, 'matchMedia', {
|
|
34
|
-
writable: true,
|
|
35
|
-
value: vi.fn().mockImplementation((query) => ({
|
|
36
|
-
matches: false,
|
|
37
|
-
media: query,
|
|
38
|
-
onchange: null,
|
|
39
|
-
addListener: vi.fn(),
|
|
40
|
-
removeListener: vi.fn(),
|
|
41
|
-
addEventListener: vi.fn(),
|
|
42
|
-
removeEventListener: vi.fn(),
|
|
43
|
-
dispatchEvent: vi.fn(),
|
|
44
|
-
})),
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Mock IntersectionObserver
|
|
48
|
-
(globalThis as any).IntersectionObserver = class IntersectionObserver {
|
|
49
|
-
constructor() {}
|
|
50
|
-
disconnect() {}
|
|
51
|
-
observe() {}
|
|
52
|
-
takeRecords() {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
unobserve() {}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// Mock crypto for UUID generation and Web Crypto API
|
|
59
|
-
// The subtle mock provides functional encryption/decryption for tests
|
|
60
|
-
const mockSubtle = {
|
|
61
|
-
// SHA-256 digest - returns deterministic hash based on input
|
|
62
|
-
digest: async (_algorithm: string, data: ArrayBuffer): Promise<ArrayBuffer> => {
|
|
63
|
-
const input = new Uint8Array(data);
|
|
64
|
-
const result = new Uint8Array(32);
|
|
65
|
-
// Simple deterministic "hash" for testing - XOR bytes into result
|
|
66
|
-
for (let i = 0; i < input.length; i++) {
|
|
67
|
-
result[i % 32] ^= input[i];
|
|
68
|
-
}
|
|
69
|
-
return result.buffer;
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
// Import key material for PBKDF2
|
|
73
|
-
importKey: async (
|
|
74
|
-
_format: string,
|
|
75
|
-
_keyData: ArrayBuffer,
|
|
76
|
-
_algorithm: string,
|
|
77
|
-
_extractable: boolean,
|
|
78
|
-
_keyUsages: string[]
|
|
79
|
-
): Promise<CryptoKey> => {
|
|
80
|
-
return { type: 'secret' } as CryptoKey;
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
// Derive key using PBKDF2
|
|
84
|
-
deriveKey: async (
|
|
85
|
-
_algorithm: object,
|
|
86
|
-
_baseKey: CryptoKey,
|
|
87
|
-
_derivedKeyType: object,
|
|
88
|
-
_extractable: boolean,
|
|
89
|
-
_keyUsages: string[]
|
|
90
|
-
): Promise<CryptoKey> => {
|
|
91
|
-
return { type: 'secret' } as CryptoKey;
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
// AES-GCM encrypt - simple XOR for reversible mock encryption
|
|
95
|
-
encrypt: async (
|
|
96
|
-
_algorithm: { name: string; iv: Uint8Array },
|
|
97
|
-
_key: CryptoKey,
|
|
98
|
-
data: ArrayBuffer
|
|
99
|
-
): Promise<ArrayBuffer> => {
|
|
100
|
-
const input = new Uint8Array(data);
|
|
101
|
-
const output = new Uint8Array(input.length);
|
|
102
|
-
for (let i = 0; i < input.length; i++) {
|
|
103
|
-
output[i] = input[i] ^ 42; // Simple XOR with constant
|
|
104
|
-
}
|
|
105
|
-
return output.buffer;
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
// AES-GCM decrypt - reverse of encrypt
|
|
109
|
-
decrypt: async (
|
|
110
|
-
_algorithm: { name: string; iv: Uint8Array },
|
|
111
|
-
_key: CryptoKey,
|
|
112
|
-
data: ArrayBuffer
|
|
113
|
-
): Promise<ArrayBuffer> => {
|
|
114
|
-
const input = new Uint8Array(data);
|
|
115
|
-
const output = new Uint8Array(input.length);
|
|
116
|
-
for (let i = 0; i < input.length; i++) {
|
|
117
|
-
output[i] = input[i] ^ 42; // XOR with same constant reverses encryption
|
|
118
|
-
}
|
|
119
|
-
return output.buffer;
|
|
120
|
-
},
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
Object.defineProperty(globalThis, 'crypto', {
|
|
124
|
-
value: {
|
|
125
|
-
randomUUID: () => 'test-uuid-' + Math.random().toString(36).substring(2, 15),
|
|
126
|
-
getRandomValues: (arr: Uint8Array) => {
|
|
127
|
-
for (let i = 0; i < arr.length; i++) {
|
|
128
|
-
arr[i] = Math.floor(Math.random() * 256);
|
|
129
|
-
}
|
|
130
|
-
return arr;
|
|
131
|
-
},
|
|
132
|
-
subtle: mockSubtle,
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
// Global test timeout
|
|
137
|
-
vi.setConfig({ testTimeout: 10000 });
|
|
138
|
-
|
|
139
|
-
console.log('✅ Test environment setup complete');
|
package/tests/vitest.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="vitest/globals" />
|
package/vitest.config.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vitest/config';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
test: {
|
|
6
|
-
globals: true,
|
|
7
|
-
environment: 'jsdom',
|
|
8
|
-
setupFiles: ['./tests/setup.ts'],
|
|
9
|
-
include: ['tests/**/*.test.{ts,tsx}'],
|
|
10
|
-
testTimeout: 10000, // 10 seconds timeout for tests
|
|
11
|
-
hookTimeout: 10000, // 10 seconds timeout for hooks
|
|
12
|
-
pool: 'forks', // Use forks pool for better isolation in CI
|
|
13
|
-
poolOptions: {
|
|
14
|
-
forks: {
|
|
15
|
-
singleFork: true, // Use single fork to reduce memory usage
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
coverage: {
|
|
19
|
-
provider: 'v8',
|
|
20
|
-
reporter: ['text', 'json', 'html', 'lcov'],
|
|
21
|
-
include: ['src/**/*.{ts,tsx}'],
|
|
22
|
-
exclude: [
|
|
23
|
-
'node_modules/',
|
|
24
|
-
'tests/',
|
|
25
|
-
'dist/',
|
|
26
|
-
'**/*.d.ts',
|
|
27
|
-
'**/*.config.*',
|
|
28
|
-
'**/mockData.ts',
|
|
29
|
-
'**/testUtils.tsx',
|
|
30
|
-
'**/testUtils.ts',
|
|
31
|
-
],
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
resolve: {
|
|
35
|
-
alias: {
|
|
36
|
-
'@': path.resolve(__dirname, './src'),
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
});
|