@qlover/create-app 0.9.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/next-app/.env.template +9 -10
  5. package/dist/templates/next-app/eslint.config.mjs +5 -0
  6. package/dist/templates/next-app/migrations/schema/UserSchema.ts +17 -3
  7. package/dist/templates/next-app/next.config.ts +1 -1
  8. package/dist/templates/next-app/package.json +2 -3
  9. package/dist/templates/next-app/src/app/[locale]/login/page.tsx +1 -1
  10. package/dist/templates/next-app/src/app/[locale]/page.tsx +1 -1
  11. package/dist/templates/next-app/src/app/[locale]/register/page.tsx +1 -1
  12. package/dist/templates/next-app/src/app/api/locales/json/route.ts +2 -1
  13. package/dist/templates/next-app/src/base/cases/DialogHandler.ts +1 -2
  14. package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +4 -5
  15. package/dist/templates/next-app/src/base/cases/UserServiceApi.ts +44 -29
  16. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +1 -2
  17. package/dist/templates/next-app/src/base/port/AppUserApiInterface.ts +22 -10
  18. package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +17 -9
  19. package/dist/templates/next-app/src/base/services/ResourceService.ts +3 -4
  20. package/dist/templates/next-app/src/base/services/UserService.ts +37 -13
  21. package/dist/templates/next-app/src/base/services/appApi/AppApiRequester.ts +8 -7
  22. package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +15 -26
  23. package/dist/templates/next-app/src/core/clientIoc/ClientIOC.ts +4 -3
  24. package/dist/templates/next-app/src/core/clientIoc/ClientIOCRegister.ts +4 -3
  25. package/dist/templates/next-app/src/core/globals.ts +2 -1
  26. package/dist/templates/next-app/src/core/serverIoc/ServerIOC.ts +4 -3
  27. package/dist/templates/next-app/src/core/serverIoc/ServerIOCRegister.ts +5 -6
  28. package/dist/templates/next-app/src/i18n/request.ts +2 -2
  29. package/dist/templates/next-app/src/server/UserCredentialToken.ts +1 -3
  30. package/dist/templates/next-app/src/uikit/components/LocaleLink.tsx +1 -2
  31. package/dist/templates/react-app/__tests__/__mocks__/{MockAppConfit.ts → MockAppConfig.ts} +1 -1
  32. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +10 -17
  33. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +27 -8
  34. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -1
  35. package/dist/templates/react-app/__tests__/__mocks__/i18nextHttpBackend.ts +110 -0
  36. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +3 -2
  37. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +13 -0
  38. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +3 -1
  39. package/dist/templates/react-app/config/IOCIdentifier.ts +9 -6
  40. package/dist/templates/react-app/config/common.ts +38 -0
  41. package/dist/templates/react-app/config/feapi.mock.json +5 -12
  42. package/dist/templates/react-app/eslint.config.mjs +6 -5
  43. package/dist/templates/react-app/package.json +1 -1
  44. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +22 -13
  45. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +3 -3
  46. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +17 -12
  47. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +19 -2
  48. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +2 -4
  49. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +15 -9
  50. package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +55 -0
  51. package/dist/templates/react-app/src/base/services/I18nService.ts +1 -0
  52. package/dist/templates/react-app/src/base/services/UserBootstrap.ts +43 -0
  53. package/dist/templates/react-app/src/base/services/UserGatewayPlugin.ts +16 -0
  54. package/dist/templates/react-app/src/base/services/UserService.ts +51 -80
  55. package/dist/templates/react-app/src/core/bootstraps/BootstrapClient.ts +8 -3
  56. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +6 -6
  57. package/dist/templates/react-app/src/core/bootstraps/SaveAppInfo.ts +28 -0
  58. package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +24 -18
  59. package/dist/templates/react-app/src/core/globals.ts +10 -11
  60. package/dist/templates/react-app/src/main.tsx +1 -1
  61. package/dist/templates/react-app/src/pages/auth/Layout.tsx +4 -4
  62. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +1 -1
  63. package/dist/templates/react-app/src/pages/base/Layout.tsx +3 -3
  64. package/dist/templates/react-app/src/uikit/components/BaseLayoutProvider.tsx +44 -0
  65. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +1 -3
  66. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +9 -0
  67. package/dist/templates/react-app/src/uikit/hooks/{useI18nGuard.ts → useRouterI18nGuard.ts} +7 -4
  68. package/dist/templates/react-app/tsconfig.app.json +1 -1
  69. package/package.json +3 -3
  70. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +0 -102
  71. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +0 -61
  72. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +0 -57
  73. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +0 -28
  74. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +0 -16
@@ -14,8 +14,8 @@ import { RequestStatusCatcher } from '@/base/cases/RequestStatusCatcher';
14
14
  import type { IocRegisterOptions } from '@/base/port/IOCInterface';
15
15
  import type { UserServiceInterface } from '@/base/port/UserServiceInterface';
16
16
  import { I18nService } from '@/base/services/I18nService';
17
- import { ProcesserExecutor } from '@/base/services/ProcesserExecutor';
18
17
  import { RouteService } from '@/base/services/RouteService';
18
+ import { UserGatewayPlugin } from '@/base/services/UserGatewayPlugin';
19
19
  import { UserService } from '@/base/services/UserService';
20
20
  import { ExecutorPageBridge } from '@/uikit/bridges/ExecutorPageBridge';
21
21
  import { JSONStoragePageBridge } from '@/uikit/bridges/JSONStoragePageBridge';
@@ -28,7 +28,6 @@ import type {
28
28
  IOCContainerInterface,
29
29
  IOCRegisterInterface
30
30
  } from '@qlover/corekit-bridge';
31
- import type { SyncStorageInterface } from '@qlover/fe-corekit';
32
31
  import type { LoggerInterface } from '@qlover/logger';
33
32
 
34
33
  export class ClientIOCRegister
@@ -71,30 +70,34 @@ export class ClientIOCRegister
71
70
  */
72
71
  protected registerImplement(ioc: IOCContainerInterface): void {
73
72
  ioc.bind(I.I18nServiceInterface, new I18nService(this.options.pathname));
74
- ioc.bind(
75
- I.RouteServiceInterface,
76
- new RouteService(
77
- ioc.get(NavigateBridge),
78
- ioc.get(I.I18nServiceInterface),
79
- {
80
- routes: useLocaleRoutes ? baseRoutes : baseNoLocaleRoutes,
81
- logger: ioc.get(I.Logger),
82
- hasLocalRoutes: useLocaleRoutes,
83
- routerPrefix: routerPrefix
84
- }
85
- )
73
+
74
+ const routeService = new RouteService(
75
+ ioc.get(NavigateBridge),
76
+ ioc.get(I.I18nServiceInterface),
77
+ {
78
+ routes: useLocaleRoutes ? baseRoutes : baseNoLocaleRoutes,
79
+ logger: ioc.get(I.Logger),
80
+ hasLocalRoutes: useLocaleRoutes,
81
+ routerPrefix: routerPrefix
82
+ }
86
83
  );
84
+ ioc.bind(I.RouteServiceInterface, routeService);
87
85
  ioc.bind(
88
86
  I.ThemeService,
89
87
  new ThemeService({
90
88
  ...(themeConfig as unknown as ThemeServiceProps),
91
- storage: ioc.get<SyncStorageInterface<string, string>>(I.LocalStorage)
89
+ storage: ioc.get(I.LocalStorage)
92
90
  })
93
91
  );
94
92
 
95
93
  ioc.bind(I.I18nKeyErrorPlugin, ioc.get(I18nKeyErrorPlugin));
96
- ioc.bind(I.ProcesserExecutorInterface, ioc.get(ProcesserExecutor));
97
- ioc.bind(I.UserServiceInterface, ioc.get(UserService));
94
+
95
+ ioc.bind(
96
+ I.UserServiceInterface,
97
+ ioc
98
+ .get<UserServiceInterface>(UserService)
99
+ .use(new UserGatewayPlugin(routeService))
100
+ );
98
101
  ioc.bind(I.RequestCatcherInterface, ioc.get(RequestStatusCatcher));
99
102
  ioc.bind(I.ExecutorPageBridgeInterface, ioc.get(ExecutorPageBridge));
100
103
  ioc.bind(I.JSONStoragePageInterface, ioc.get(JSONStoragePageBridge));
@@ -111,7 +114,10 @@ export class ClientIOCRegister
111
114
  token: () =>
112
115
  ioc.get<UserServiceInterface>(I.UserServiceInterface).getToken()
113
116
  });
114
- const apiMockPlugin = new ApiMockPlugin(mockDataJson, logger);
117
+ const apiMockPlugin = new ApiMockPlugin({
118
+ mockData: mockDataJson,
119
+ logger: logger
120
+ });
115
121
  const apiCatchPlugin = new ApiCatchPlugin(
116
122
  logger,
117
123
  ioc.get(RequestStatusCatcher)
@@ -1,17 +1,13 @@
1
1
  // ! global variables, don't import any dependencies and don't have side effects
2
2
  import { loggerStyles } from '@config/common';
3
- import {
4
- ColorFormatter,
5
- ConsoleHandler,
6
- CookieStorage,
7
- Logger
8
- } from '@qlover/corekit-bridge';
3
+ import { ColorFormatter, CookieStorage } from '@qlover/corekit-bridge';
9
4
  import {
10
5
  Base64Serializer,
11
6
  JSONSerializer,
12
7
  ObjectStorage,
13
8
  SyncStorage
14
9
  } from '@qlover/fe-corekit';
10
+ import { Logger, ConsoleHandler } from '@qlover/logger';
15
11
  import { AppConfig } from '@/base/cases/AppConfig';
16
12
  import { DialogHandler } from '@/base/cases/DialogHandler';
17
13
  import type { SyncStorageInterface } from '@qlover/fe-corekit';
@@ -37,11 +33,14 @@ export const JSON = new JSONSerializer();
37
33
  /**
38
34
  * Override localStorage to use the global local storage
39
35
  */
40
- export const localStorage = new SyncStorage(new ObjectStorage(), [
41
- JSON,
42
- new Base64Serializer(),
43
- window.localStorage as unknown as SyncStorageInterface<string>
44
- ]);
36
+ export const localStorage = new SyncStorage<string>(
37
+ new ObjectStorage(),
38
+ [
39
+ JSON,
40
+ appConfig.isProduction ? new Base64Serializer() : undefined,
41
+ window.localStorage as unknown as SyncStorageInterface<string>
42
+ ].filter(Boolean) as any[]
43
+ );
45
44
 
46
45
  export const localStorageEncrypt = localStorage;
47
46
 
@@ -4,7 +4,7 @@ import { StrictMode } from 'react';
4
4
  import { createRoot } from 'react-dom/client';
5
5
  import App from './App.tsx';
6
6
  import { BootstrapClient } from './core/bootstraps/BootstrapClient';
7
- import { clientIOC } from './core/clientIoc/ClientIOC.ts';
7
+ import { clientIOC } from './core/clientIoc/ClientIOC';
8
8
 
9
9
  BootstrapClient.main({
10
10
  root: window,
@@ -1,18 +1,18 @@
1
1
  import { useStore } from '@brain-toolkit/react-kit/hooks/useStore';
2
2
  import { IOCIdentifier } from '@config/IOCIdentifier';
3
3
  import { Navigate, Outlet } from 'react-router-dom';
4
- import { useI18nGuard } from '@/uikit/hooks/useI18nGuard';
5
4
  import { useIOC } from '@/uikit/hooks/useIOC';
5
+ import { useRouterI18nGuard } from '@/uikit/hooks/useRouterI18nGuard';
6
6
  import { BaseHeader } from '../../uikit/components/BaseHeader';
7
7
 
8
8
  export default function Layout() {
9
9
  const userService = useIOC(IOCIdentifier.UserServiceInterface);
10
- useStore(userService.store);
10
+ const state = useStore(userService.getStore());
11
11
 
12
- useI18nGuard();
12
+ useRouterI18nGuard();
13
13
 
14
14
  // If user is authenticated, redirect to home page
15
- if (userService.isAuthenticated()) {
15
+ if (userService.isAuthenticated() && userService.isUserInfo(state.result)) {
16
16
  return <Navigate data-testid="Layout" to="/" replace />;
17
17
  }
18
18
 
@@ -3,7 +3,7 @@ import { register18n } from '@config/i18n/register18n';
3
3
  import { IOCIdentifier } from '@config/IOCIdentifier';
4
4
  import { Form, Input, Button, Checkbox } from 'antd';
5
5
  import { useState } from 'react';
6
- import type { RegisterFormData } from '@/base/services/UserService';
6
+ import type { RegisterFormData } from '@/base/apis/userApi/UserApiType';
7
7
  import { useI18nInterface } from '@/uikit/hooks/useI18nInterface';
8
8
  import { useIOC } from '@/uikit/hooks/useIOC';
9
9
 
@@ -1,10 +1,10 @@
1
1
  import { Outlet } from 'react-router-dom';
2
- import { ProcessExecutorProvider } from '@/uikit/components/ProcessExecutorProvider';
2
+ import { BaseLayoutProvider } from '@/uikit/components/BaseLayoutProvider';
3
3
  import { BaseHeader } from '../../uikit/components/BaseHeader';
4
4
 
5
5
  export default function Layout() {
6
6
  return (
7
- <ProcessExecutorProvider data-testid="Layout">
7
+ <BaseLayoutProvider data-testid="Layout">
8
8
  <div
9
9
  data-testid="basic-layout"
10
10
  className="text-base min-h-screen bg-primary"
@@ -15,6 +15,6 @@ export default function Layout() {
15
15
  <Outlet />
16
16
  </div>
17
17
  </div>
18
- </ProcessExecutorProvider>
18
+ </BaseLayoutProvider>
19
19
  );
20
20
  }
@@ -0,0 +1,44 @@
1
+ import { useStore } from '@brain-toolkit/react-kit';
2
+ import { I } from '@config/IOCIdentifier';
3
+ import { BaseLayoutService } from '@/base/services/BaseLayoutService';
4
+ import { Loading } from './Loading';
5
+ import { useIOC } from '../hooks/useIOC';
6
+ import { useNavigateBridge } from '../hooks/useNavigateBridge';
7
+ import { useRouterI18nGuard } from '../hooks/useRouterI18nGuard';
8
+ import { useStrictEffect } from '../hooks/useStrictEffect';
9
+
10
+ /**
11
+ * BaseLayoutProvider
12
+ *
13
+ * /pages/base/Layout.tsx 布局组件的服务提供者
14
+ *
15
+ * - 验证用户信息渲染组件,如果用户未登录则渲染 loading
16
+ *
17
+ * @param children - The children to render
18
+ * @returns
19
+ */
20
+ export function BaseLayoutProvider({
21
+ children
22
+ }: {
23
+ children: React.ReactNode;
24
+ }) {
25
+ const ioc = useIOC();
26
+ const baseLayoutService = ioc(BaseLayoutService);
27
+ const userService = ioc(I.UserServiceInterface);
28
+
29
+ useStore(userService.getStore());
30
+
31
+ useRouterI18nGuard();
32
+
33
+ useNavigateBridge();
34
+
35
+ useStrictEffect(() => {
36
+ baseLayoutService.use(ioc(I.I18nKeyErrorPlugin)).starup(ioc);
37
+ }, []);
38
+
39
+ if (!userService.isAuthenticated()) {
40
+ return <Loading data-testid="BaseLayoutProviderLoading" fullscreen />;
41
+ }
42
+
43
+ return children;
44
+ }
@@ -29,9 +29,7 @@ export function LogoutButton() {
29
29
  'data-testid': 'LogoutButton-CancelButton'
30
30
  },
31
31
  content: tContent,
32
- onOk: () => {
33
- userService.logout();
34
- }
32
+ onOk: () => userService.logout()
35
33
  });
36
34
  }, [tTitle, tContent]);
37
35
 
@@ -3,6 +3,15 @@ import { useNavigate } from 'react-router-dom';
3
3
  import { useIOC } from './useIOC';
4
4
  import { NavigateBridge } from '../bridges/NavigateBridge';
5
5
 
6
+ /**
7
+ * 使用 navigate 桥接
8
+ *
9
+ * 将 navigate 桥接到 NavigateBridge 中
10
+ *
11
+ * 这样就可以在服务层使用 navigate 了, 比如在某个service中需要跳转页面,就可以使用 navigateBridge.getUIBridge() 来跳转
12
+ *
13
+ * **但是它需要在 RouterProvider 中使用**
14
+ */
6
15
  export function useNavigateBridge() {
7
16
  const navigate = useNavigate();
8
17
  const navigateBridge = useIOC(NavigateBridge);
@@ -5,13 +5,16 @@ import type { LocaleType } from '@config/i18n/i18nConfig';
5
5
  import { useIOC } from './useIOC';
6
6
 
7
7
  /**
8
- * Language Guard
8
+ * 国际化路由国际化守卫
9
9
  *
10
- * if language not found, redirect to 404 page
10
+ * 比如: 开启了 `@config/common 中useLocaleRoutes` `true` 时,
11
+ *
12
+ * 访问 `/login` 则会自动重定向到 `/en/login`, 其中 en 为默认语言可配置
13
+ *
14
+ * 或者访问一个不支持的语言,则会自动重定向到 `/en/404`
11
15
  *
12
- * TODO: if language not found, use default language
13
16
  */
14
- export function useI18nGuard() {
17
+ export function useRouterI18nGuard() {
15
18
  const { lng } = useParams<{ lng: LocaleType }>();
16
19
  const { pathname } = useLocation();
17
20
  const navigate = useNavigate();
@@ -32,5 +32,5 @@
32
32
  }
33
33
  },
34
34
  "include": ["src", "config"],
35
- "exclude": ["node_modules", "dist"]
35
+ "exclude": ["**/**/node_modules", "**/**dist"]
36
36
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qlover/create-app",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "Create a new app with a single command",
5
5
  "private": false,
6
6
  "type": "module",
@@ -33,12 +33,12 @@
33
33
  "ignore": "^7.0.3",
34
34
  "lodash": "^4.17.21",
35
35
  "ora": "^8.1.1",
36
- "@qlover/logger": "0.2.0"
36
+ "@qlover/logger": "0.3.0"
37
37
  },
38
38
  "dependencies": {
39
39
  "commander": "^13.1.0",
40
40
  "inquirer": "^12.3.2",
41
- "@qlover/scripts-context": "1.1.4"
41
+ "@qlover/scripts-context": "1.2.0"
42
42
  },
43
43
  "scripts": {
44
44
  "lint": "eslint src --fix",
@@ -1,102 +0,0 @@
1
- /**
2
- * AppError test suite
3
- *
4
- * Coverage:
5
- * 1. constructor - Constructor initialization with different source types
6
- * 2. inheritance - Verify inheritance from ExecutorError
7
- * 3. error properties - Verify error properties are set correctly
8
- */
9
-
10
- import { ExecutorError } from '@qlover/fe-corekit';
11
- import { describe, it, expect } from 'vitest';
12
- import { AppError } from '@/base/cases/AppError';
13
-
14
- describe('AppError', () => {
15
- describe('constructor', () => {
16
- it('should create instance with id only', () => {
17
- const error = new AppError('TEST_ERROR');
18
- expect(error).toBeInstanceOf(AppError);
19
- expect(error).toBeInstanceOf(ExecutorError);
20
- expect(error).toBeInstanceOf(Error);
21
- expect(error.id).toBe('TEST_ERROR');
22
- expect(error.message).toBe('TEST_ERROR');
23
- expect(error.source).toBeUndefined();
24
- });
25
-
26
- it('should create instance with string source', () => {
27
- const source = 'Test error message';
28
- const error = new AppError('TEST_ERROR', source);
29
- expect(error.id).toBe('TEST_ERROR');
30
- expect(error.message).toBe(source);
31
- expect(error.source).toBe(source);
32
- });
33
-
34
- it('should create instance with Error source', () => {
35
- const source = new Error('Original error');
36
- const error = new AppError('TEST_ERROR', source);
37
- expect(error.id).toBe('TEST_ERROR');
38
- expect(error.message).toBe('Original error');
39
- expect(error.source).toBe(source);
40
- });
41
- });
42
-
43
- describe('error properties', () => {
44
- it('should have correct error type', () => {
45
- const error = new AppError('TEST_ERROR');
46
- expect(error.id).toBe('TEST_ERROR');
47
- });
48
-
49
- it('should maintain id property', () => {
50
- const error = new AppError('TEST_ERROR');
51
- Object.defineProperty(error, 'id', { value: 'NEW_ID' });
52
- expect(error.id).toBe('NEW_ID');
53
- });
54
-
55
- it('should maintain source property', () => {
56
- const source = 'source';
57
- const error = new AppError('TEST_ERROR', source);
58
- Object.defineProperty(error, 'source', { value: 'new source' });
59
- expect(error.source).toBe('new source');
60
- });
61
- });
62
-
63
- describe('error handling', () => {
64
- it('should work in try-catch block', () => {
65
- expect(() => {
66
- throw new AppError('TEST_ERROR');
67
- }).toThrow(AppError);
68
- });
69
-
70
- it('should preserve stack trace', () => {
71
- const error = new AppError('TEST_ERROR');
72
- expect(error.stack).toBeDefined();
73
- expect(error.stack).toContain('AppError.test.ts');
74
- });
75
-
76
- it('should handle nested errors', () => {
77
- const originalError = new Error('Original error');
78
- const wrappedError = new AppError('WRAPPED_ERROR', originalError);
79
- expect(wrappedError.source).toBe(originalError);
80
- expect(wrappedError.message).toBe('Original error');
81
- });
82
- });
83
-
84
- describe('error message formatting', () => {
85
- it('should use id as message when source is undefined', () => {
86
- const error = new AppError('TEST_ERROR');
87
- expect(error.message).toBe('TEST_ERROR');
88
- });
89
-
90
- it('should use source message when source is Error', () => {
91
- const source = new Error('Source error message');
92
- const error = new AppError('TEST_ERROR', source);
93
- expect(error.message).toBe('Source error message');
94
- });
95
-
96
- it('should use source string when source is string', () => {
97
- const source = 'Source error message';
98
- const error = new AppError('TEST_ERROR', source);
99
- expect(error.message).toBe('Source error message');
100
- });
101
- });
102
- });
@@ -1,61 +0,0 @@
1
- import { readFileSync, existsSync } from 'fs';
2
- import { join } from 'path';
3
-
4
- describe('main.tsx Integration Tests', () => {
5
- beforeAll(() => {
6
- // Setup test environment
7
- if (!document.getElementById('root')) {
8
- const rootElement = document.createElement('div');
9
- rootElement.id = 'root';
10
- document.body.appendChild(rootElement);
11
- }
12
- });
13
-
14
- afterAll(() => {
15
- // Clean up DOM
16
- const rootElement = document.getElementById('root');
17
- if (rootElement) {
18
- rootElement.remove();
19
- }
20
- });
21
-
22
- beforeEach(() => {
23
- // Clean up root element content
24
- const rootElement = document.getElementById('root');
25
- if (rootElement) {
26
- rootElement.innerHTML = '';
27
- }
28
- });
29
-
30
- it('should have main.tsx file', () => {
31
- // Test if file exists
32
- const mainPath = join(process.cwd(), 'src/main.tsx');
33
- expect(existsSync(mainPath)).toBe(true);
34
- });
35
-
36
- it('should have main.tsx with correct structure', () => {
37
- // Test file content structure
38
- const mainPath = join(process.cwd(), 'src/main.tsx');
39
- const content = readFileSync(mainPath, 'utf-8');
40
-
41
- // Check if it contains necessary imports
42
- expect(content).toContain('import');
43
- expect(content).toContain('BootstrapClient');
44
- expect(content).toContain('createRoot');
45
- });
46
-
47
- it('should have App.tsx file', () => {
48
- // Test if App.tsx file exists
49
- const appPath = join(process.cwd(), 'src/App.tsx');
50
- expect(existsSync(appPath)).toBe(true);
51
- });
52
-
53
- it('should have BootstrapClient.ts file', () => {
54
- // Test if BootstrapClient.ts file exists
55
- const bootstrapPath = join(
56
- process.cwd(),
57
- 'src/core/bootstraps/BootstrapClient.ts'
58
- );
59
- expect(existsSync(bootstrapPath)).toBe(true);
60
- });
61
- });
@@ -1,57 +0,0 @@
1
- import { IOCIdentifier } from '@config/IOCIdentifier';
2
- import {
3
- AsyncExecutor,
4
- ExecutorContext,
5
- ExecutorPlugin
6
- } from '@qlover/fe-corekit';
7
- import { injectable, inject } from 'inversify';
8
- import type { ProcesserExecutorInterface } from '../port/ProcesserExecutorInterface';
9
- import type { RouteServiceInterface } from '../port/RouteServiceInterface';
10
- import type { BootstrapContextValue } from '@qlover/corekit-bridge';
11
- import type { LoggerInterface } from '@qlover/logger';
12
-
13
- @injectable()
14
- export class ProcesserExecutor implements ProcesserExecutorInterface {
15
- pluginName = 'ProcesserExecutor';
16
- protected executor: AsyncExecutor = new AsyncExecutor();
17
-
18
- constructor(
19
- @inject(IOCIdentifier.Logger) protected logger: LoggerInterface,
20
- @inject(IOCIdentifier.RouteServiceInterface)
21
- protected routeService: RouteServiceInterface
22
- ) {}
23
-
24
- /**
25
- * @override
26
- */
27
- onBefore({
28
- parameters: { ioc }
29
- }: ExecutorContext<BootstrapContextValue>): void | Promise<void> {
30
- this.use(ioc.get(IOCIdentifier.I18nKeyErrorPlugin));
31
- this.use(ioc.get(IOCIdentifier.UserServiceInterface));
32
- }
33
-
34
- use(plugin: ExecutorPlugin): this {
35
- this.executor.use(plugin);
36
- return this;
37
- }
38
-
39
- handler(): Promise<{ success: boolean }> {
40
- return Promise.resolve({
41
- success: true
42
- });
43
- }
44
-
45
- async starup(): Promise<unknown> {
46
- this.logger.info('PageProcesser startup');
47
-
48
- try {
49
- const result = await this.executor.exec(this.handler);
50
- return result;
51
- } catch (err) {
52
- this.logger.error('PageProcesser init failed', err);
53
-
54
- this.routeService.gotoLogin();
55
- }
56
- }
57
- }
@@ -1,28 +0,0 @@
1
- import { IOCIdentifier } from '@config/IOCIdentifier';
2
- import { UserAuthProvider } from './UserAuthProvider';
3
- import { useI18nGuard } from '../hooks/useI18nGuard';
4
- import { useIOC } from '../hooks/useIOC';
5
- import { useNavigateBridge } from '../hooks/useNavigateBridge';
6
- import { useStrictEffect } from '../hooks/useStrictEffect';
7
-
8
- export function ProcessExecutorProvider({
9
- children
10
- }: {
11
- children: React.ReactNode;
12
- }) {
13
- const processerExecutor = useIOC(IOCIdentifier.ProcesserExecutorInterface);
14
-
15
- useI18nGuard();
16
-
17
- useNavigateBridge();
18
-
19
- useStrictEffect(() => {
20
- processerExecutor.starup();
21
- }, []);
22
-
23
- return (
24
- <UserAuthProvider data-testid="ProcessExecutorProvider">
25
- {children}
26
- </UserAuthProvider>
27
- );
28
- }
@@ -1,16 +0,0 @@
1
- import { useStore } from '@brain-toolkit/react-kit/hooks/useStore';
2
- import { IOCIdentifier } from '@config/IOCIdentifier';
3
- import { Loading } from './Loading';
4
- import { useIOC } from '../hooks/useIOC';
5
-
6
- export function UserAuthProvider({ children }: { children: React.ReactNode }) {
7
- const userService = useIOC(IOCIdentifier.UserServiceInterface);
8
-
9
- useStore(userService.store);
10
-
11
- if (!userService.isAuthenticated()) {
12
- return <Loading data-testid="UserAuthProvider" fullscreen />;
13
- }
14
-
15
- return children;
16
- }