@akanjs/config 0.0.4
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 +11 -0
- package/index.d.ts +1 -0
- package/index.js +27 -0
- package/package.json +76 -0
- package/src/PageAgent.d.ts +13 -0
- package/src/PageAgent.js +67 -0
- package/src/PageAgent.ts +42 -0
- package/src/jest.config.base.d.ts +2 -0
- package/src/jest.config.base.js +49 -0
- package/src/jest.config.base.ts +25 -0
- package/src/jest.globalSetup.d.ts +4 -0
- package/src/jest.globalSetup.js +38 -0
- package/src/jest.globalSetup.ts +27 -0
- package/src/jest.globalTeardown.d.ts +3 -0
- package/src/jest.globalTeardown.js +30 -0
- package/src/jest.globalTeardown.ts +12 -0
- package/src/jest.preset.js +3 -0
- package/src/jest.setupFilesAfterEnv.d.ts +1 -0
- package/src/jest.setupFilesAfterEnv.js +10 -0
- package/src/jest.setupFilesAfterEnv.ts +17 -0
- package/src/next.base.js +127 -0
- package/src/playwright.config.base.d.ts +9 -0
- package/src/playwright.config.base.js +80 -0
- package/src/playwright.config.base.ts +71 -0
- package/src/tailwind.base.js +351 -0
- package/src/testServer.d.ts +12 -0
- package/src/testServer.js +139 -0
- package/src/testServer.ts +105 -0
- package/src/tsconfig.backend.json +24 -0
- package/src/webpack.backend.base.js +42 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { type BackendEnv } from "@akanjs/base";
|
|
2
|
+
import { Logger, sleep } from "@akanjs/common";
|
|
3
|
+
import { type BackendApp, createNestApp } from "@akanjs/server";
|
|
4
|
+
import { client } from "@akanjs/signal";
|
|
5
|
+
import { DynamicModule } from "@nestjs/common";
|
|
6
|
+
import { MongoMemoryServer } from "mongodb-memory-server";
|
|
7
|
+
import mongoose from "mongoose";
|
|
8
|
+
import { RedisMemoryServer } from "redis-memory-server";
|
|
9
|
+
|
|
10
|
+
const MAX_RETRY = 5;
|
|
11
|
+
const TEST_LISTEN_PORT_BASE = 38080;
|
|
12
|
+
const TEST_MONGODB_PORT_BASE = 38081;
|
|
13
|
+
const TEST_REDIS_PORT_BASE = 38082;
|
|
14
|
+
const MIN_ACTIVATION_TIME = 0;
|
|
15
|
+
const MAX_ACTIVATION_TIME = 30000;
|
|
16
|
+
|
|
17
|
+
export class TestServer {
|
|
18
|
+
readonly #logger = new Logger("TestServer");
|
|
19
|
+
readonly #mongod: MongoMemoryServer;
|
|
20
|
+
readonly #redis: RedisMemoryServer;
|
|
21
|
+
readonly #registerModules: (options: any) => DynamicModule[];
|
|
22
|
+
readonly #env: BackendEnv;
|
|
23
|
+
workerId: number;
|
|
24
|
+
#startAt = Date.now();
|
|
25
|
+
#app: BackendApp;
|
|
26
|
+
#portOffset = 0;
|
|
27
|
+
static initClient(env: BackendEnv, workerId = parseInt(process.env.JEST_WORKER_ID ?? "0")) {
|
|
28
|
+
if (workerId === 0) throw new Error("TestClient should not be used in main thread");
|
|
29
|
+
const portOffset = workerId * 1000 + env.appCode * 10;
|
|
30
|
+
const port = TEST_LISTEN_PORT_BASE + portOffset;
|
|
31
|
+
const endpoint = `http://localhost:${port}/backend/graphql`;
|
|
32
|
+
client.init({ uri: endpoint });
|
|
33
|
+
}
|
|
34
|
+
constructor(registerModules: (options: any) => DynamicModule[], env: BackendEnv, workerId?: number) {
|
|
35
|
+
this.workerId = workerId ?? parseInt(process.env.JEST_WORKER_ID ?? "0");
|
|
36
|
+
if (this.workerId === 0) throw new Error("TestServer should not be used in main thread");
|
|
37
|
+
this.#portOffset = this.workerId * 1000 + env.appCode * 10;
|
|
38
|
+
this.#mongod = new MongoMemoryServer({ instance: { port: TEST_MONGODB_PORT_BASE + this.#portOffset } });
|
|
39
|
+
this.#redis = new RedisMemoryServer({ instance: { port: TEST_REDIS_PORT_BASE + this.#portOffset } });
|
|
40
|
+
this.#env = { ...env };
|
|
41
|
+
this.#registerModules = registerModules;
|
|
42
|
+
}
|
|
43
|
+
async init() {
|
|
44
|
+
for (let i = 0; i < MAX_RETRY; i++) {
|
|
45
|
+
try {
|
|
46
|
+
const watchdog = setTimeout(() => {
|
|
47
|
+
throw new Error("TestServer Init Timeout");
|
|
48
|
+
}, MAX_ACTIVATION_TIME);
|
|
49
|
+
await this.#init();
|
|
50
|
+
clearTimeout(watchdog);
|
|
51
|
+
return;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
this.#logger.error(e as string);
|
|
54
|
+
await this.terminate();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async #init() {
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
this.#logger.log(`Test System #${this.workerId} Initializing...`);
|
|
61
|
+
const port = TEST_LISTEN_PORT_BASE + this.#portOffset;
|
|
62
|
+
const [mongoUri, redisHost, redisPort] = await Promise.all([
|
|
63
|
+
this.startMongo(),
|
|
64
|
+
this.#redis.getHost(),
|
|
65
|
+
this.#redis.getPort(),
|
|
66
|
+
]);
|
|
67
|
+
this.#env.port = port;
|
|
68
|
+
this.#env.mongoUri = mongoUri;
|
|
69
|
+
this.#env.redisUri = `redis://${redisHost}:${redisPort}`;
|
|
70
|
+
this.#env.meiliUri = "http://localhost:7700/search";
|
|
71
|
+
this.#env.onCleanup = async () => {
|
|
72
|
+
await this.cleanup();
|
|
73
|
+
};
|
|
74
|
+
this.#app = await createNestApp({ registerModules: this.#registerModules, env: this.#env });
|
|
75
|
+
this.#logger.log(`Test System #${this.workerId} Initialized, Mongo: ${mongoUri}, Redis: ${redisHost}:${redisPort}`);
|
|
76
|
+
this.#startAt = Date.now();
|
|
77
|
+
this.#logger.log(`Test System #${this.workerId} Activation Time: ${this.#startAt - now}ms`);
|
|
78
|
+
}
|
|
79
|
+
async startMongo() {
|
|
80
|
+
await this.#mongod.start();
|
|
81
|
+
return this.#mongod.getUri();
|
|
82
|
+
}
|
|
83
|
+
async cleanup() {
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
this.#logger.log("Mongo Memory Database Cleaning up...");
|
|
86
|
+
if (this.#mongod.state === "running") {
|
|
87
|
+
await this.#mongod.stop();
|
|
88
|
+
await this.#mongod.start(true);
|
|
89
|
+
}
|
|
90
|
+
this.#logger.log(`Mongo Memory Database Cleaned up in ${Date.now() - now}ms`);
|
|
91
|
+
}
|
|
92
|
+
async terminate() {
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
const elapsed = now - this.#startAt;
|
|
95
|
+
await sleep(50); // cooldown
|
|
96
|
+
client.io?.socket.close();
|
|
97
|
+
await this.#app.close();
|
|
98
|
+
if (elapsed < MIN_ACTIVATION_TIME) {
|
|
99
|
+
this.#logger.log(`waiting for ${MIN_ACTIVATION_TIME - elapsed}`);
|
|
100
|
+
await sleep(MIN_ACTIVATION_TIME - elapsed);
|
|
101
|
+
}
|
|
102
|
+
await Promise.all([mongoose.disconnect(), this.#mongod.stop(), this.#redis.stop()]);
|
|
103
|
+
this.#logger.log(`System Terminated in ${Date.now() - now}ms`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"esModuleInterop": true,
|
|
6
|
+
"target": "es2022",
|
|
7
|
+
"module": "commonjs",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"strict": false,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"incremental": true,
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"plugins": [
|
|
16
|
+
{
|
|
17
|
+
"name": "next"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"noEmit": false
|
|
21
|
+
},
|
|
22
|
+
"include": ["**/*.ts", "**/*.tsx"],
|
|
23
|
+
"exclude": ["node_modules", "jest.config.ts", "**/*.spec.ts", "**/*.test.ts"]
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { composePlugins, withNx } = require("@nx/webpack");
|
|
2
|
+
const webpack = require("webpack");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const nodeExternals = require("webpack-node-externals");
|
|
5
|
+
const { RunScriptWebpackPlugin } = require("run-script-webpack-plugin");
|
|
6
|
+
const appName = process.env.NX_TASK_TARGET_PROJECT ?? "unknown";
|
|
7
|
+
const GeneratePackageJsonPlugin = require("generate-package-json-webpack-plugin");
|
|
8
|
+
|
|
9
|
+
module.exports = composePlugins(withNx(), (config) => {
|
|
10
|
+
const tsloaderRule = config.module.rules.find((rule) => rule.loader?.includes("ts-loader"));
|
|
11
|
+
if (tsloaderRule)
|
|
12
|
+
tsloaderRule.exclude = [
|
|
13
|
+
/\.tsx$/, // Explicitly exclude .tsx files
|
|
14
|
+
/\/ui\/.*\.(ts|tsx)$/, // Exclude .ts and .tsx files in any "ui" directory
|
|
15
|
+
/\/client\/.*\.(ts|tsx)$/, // Exclude .ts and .tsx files in any "client" directory
|
|
16
|
+
/\/next\/.*\.(ts|tsx)$/, // Exclude .ts and .tsx files in any "client" directory
|
|
17
|
+
/\.store\.ts$/, // Exclude files ending with .store.ts
|
|
18
|
+
];
|
|
19
|
+
const basePackage = {
|
|
20
|
+
name: `${appName}/backend`,
|
|
21
|
+
version: "1.0.0",
|
|
22
|
+
main: "./main.js",
|
|
23
|
+
engines: { node: ">= 18" },
|
|
24
|
+
};
|
|
25
|
+
config.plugins.push(new GeneratePackageJsonPlugin(basePackage));
|
|
26
|
+
|
|
27
|
+
if (process.env.NX_TASK_TARGET_TARGET !== "serve-backend") return config;
|
|
28
|
+
Object.assign(config, {
|
|
29
|
+
entry: [path.join(__dirname, "../../../../node_modules/webpack/hot/poll?100"), `./main.ts`],
|
|
30
|
+
mode: "development",
|
|
31
|
+
output: {
|
|
32
|
+
path: path.join(__dirname, `../../../../dist/apps/${appName}/backend`),
|
|
33
|
+
filename: "main.js",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
config.plugins.push(
|
|
37
|
+
new webpack.HotModuleReplacementPlugin(),
|
|
38
|
+
new RunScriptWebpackPlugin({ name: "main.js", autoRestart: true })
|
|
39
|
+
);
|
|
40
|
+
config.externals.push(nodeExternals({ allowlist: ["webpack/hot/poll?100"] }));
|
|
41
|
+
return config;
|
|
42
|
+
});
|