@naturalcycles/backend-lib 9.83.0 → 9.84.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,7 +7,7 @@ export interface ExpressApp extends Fetcher, AsyncDisposable {
7
7
  declare class ExpressTestService {
8
8
  createAppFromResource(resource: BackendRequestHandlerCfg, opt?: FetcherOptions, defaultAppCfg?: DefaultAppCfg): Promise<ExpressApp>;
9
9
  createAppFromResources(resources: BackendRequestHandlerCfg[], opt?: FetcherOptions): Promise<ExpressApp>;
10
- createApp(app: BackendApplication, opt?: FetcherOptions): ExpressApp;
10
+ createApp(app: BackendApplication, opt?: FetcherOptions): Promise<ExpressApp>;
11
11
  /**
12
12
  * Creates a "Default Express App" with provided resources.
13
13
  * Starts an http server on '127.0.0.1' and random available port.
@@ -1,9 +1,10 @@
1
1
  import { getFetcher } from '@naturalcycles/js-lib/http';
2
2
  import { pDelay } from '@naturalcycles/js-lib/promise/pDelay.js';
3
3
  import { createDefaultApp } from '../express/createDefaultApp.js';
4
+ const TEST_SERVER_HOST = '127.0.0.1';
4
5
  const nativeFetchFn = async (url, init) => await globalThis.fetch(url, init);
5
6
  // Example:
6
- // const app = expressTestService.createApp([ debugResource ])
7
+ // const app = await expressTestService.createAppFromResource(debugResource)
7
8
  // afterAll(async () => {
8
9
  // await app.close()
9
10
  // })
@@ -19,10 +20,10 @@ class ExpressTestService {
19
20
  resources,
20
21
  }), opt);
21
22
  }
22
- createApp(app, opt) {
23
- const server = this.createTestServer(app);
23
+ async createApp(app, opt) {
24
+ const server = await this.createTestServer(app);
24
25
  const { port } = server.address();
25
- const baseUrl = `http://127.0.0.1:${port}`;
26
+ const baseUrl = `http://${TEST_SERVER_HOST}:${port}`;
26
27
  const fetcher = getFetcher({
27
28
  baseUrl,
28
29
  responseType: 'json',
@@ -63,14 +64,23 @@ class ExpressTestService {
63
64
  * const { port } = server.address() as AddressInfo
64
65
  * const url = `http://127.0.0.1:${port}`
65
66
  */
66
- createTestServer(app) {
67
+ async createTestServer(app) {
67
68
  // Important!
68
- // Only with this syntax `app.listen(0)` it allocates a port synchronously
69
- // Trying to specify a hostname will make server.address() return null.
70
- // This is how `supertest` is doing it.
71
- const server = app.listen(0);
69
+ // Listening on the same host that the Fetcher connects to.
70
+ // `app.listen(0)` (without a hostname) listens on all interfaces (`::`), and the OS (e.g macOS)
71
+ // may give it a port that some other process (e.g IntelliJ on 63342) already listens on
72
+ // at 127.0.0.1. Requests to 127.0.0.1 would then reach that other process instead.
73
+ // Listening on 127.0.0.1 makes the OS pick a port that is free on 127.0.0.1.
74
+ // The downside is that the port is only known after the async `listening` callback
75
+ // (server.address() returns null until then).
72
76
  // enableDestroy(server)
73
- return server;
77
+ return await new Promise((resolve, reject) => {
78
+ const server = app.listen(0, TEST_SERVER_HOST, (err) => {
79
+ if (err)
80
+ return reject(err);
81
+ resolve(server);
82
+ });
83
+ });
74
84
  }
75
85
  }
76
86
  export const expressTestService = new ExpressTestService();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/backend-lib",
3
3
  "type": "module",
4
- "version": "9.83.0",
4
+ "version": "9.84.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/db-lib": "^10",
7
7
  "@naturalcycles/js-lib": "^15",
@@ -7,6 +7,8 @@ import { createDefaultApp } from '../express/createDefaultApp.js'
7
7
  import type { BackendRequestHandlerCfg, DefaultAppCfg } from '../express/createDefaultApp.js'
8
8
  import type { BackendApplication } from '../server/server.model.js'
9
9
 
10
+ const TEST_SERVER_HOST = '127.0.0.1'
11
+
10
12
  const nativeFetchFn: FetchFunction = async (url, init) => await globalThis.fetch(url, init)
11
13
 
12
14
  export interface ExpressApp extends Fetcher, AsyncDisposable {
@@ -14,7 +16,7 @@ export interface ExpressApp extends Fetcher, AsyncDisposable {
14
16
  }
15
17
 
16
18
  // Example:
17
- // const app = expressTestService.createApp([ debugResource ])
19
+ // const app = await expressTestService.createAppFromResource(debugResource)
18
20
  // afterAll(async () => {
19
21
  // await app.close()
20
22
  // })
@@ -46,10 +48,10 @@ class ExpressTestService {
46
48
  )
47
49
  }
48
50
 
49
- createApp(app: BackendApplication, opt?: FetcherOptions): ExpressApp {
50
- const server = this.createTestServer(app)
51
+ async createApp(app: BackendApplication, opt?: FetcherOptions): Promise<ExpressApp> {
52
+ const server = await this.createTestServer(app)
51
53
  const { port } = server.address() as AddressInfo
52
- const baseUrl = `http://127.0.0.1:${port}`
54
+ const baseUrl = `http://${TEST_SERVER_HOST}:${port}`
53
55
 
54
56
  const fetcher = getFetcher({
55
57
  baseUrl,
@@ -95,14 +97,22 @@ class ExpressTestService {
95
97
  * const { port } = server.address() as AddressInfo
96
98
  * const url = `http://127.0.0.1:${port}`
97
99
  */
98
- private createTestServer(app: BackendApplication): Server {
100
+ private async createTestServer(app: BackendApplication): Promise<Server> {
99
101
  // Important!
100
- // Only with this syntax `app.listen(0)` it allocates a port synchronously
101
- // Trying to specify a hostname will make server.address() return null.
102
- // This is how `supertest` is doing it.
103
- const server = app.listen(0)
102
+ // Listening on the same host that the Fetcher connects to.
103
+ // `app.listen(0)` (without a hostname) listens on all interfaces (`::`), and the OS (e.g macOS)
104
+ // may give it a port that some other process (e.g IntelliJ on 63342) already listens on
105
+ // at 127.0.0.1. Requests to 127.0.0.1 would then reach that other process instead.
106
+ // Listening on 127.0.0.1 makes the OS pick a port that is free on 127.0.0.1.
107
+ // The downside is that the port is only known after the async `listening` callback
108
+ // (server.address() returns null until then).
104
109
  // enableDestroy(server)
105
- return server
110
+ return await new Promise<Server>((resolve, reject) => {
111
+ const server = app.listen(0, TEST_SERVER_HOST, (err?: Error) => {
112
+ if (err) return reject(err)
113
+ resolve(server)
114
+ })
115
+ })
106
116
  }
107
117
  }
108
118