Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,21 @@ import { isPortAvailable } from '@rstackjs/test-utils';
const available = await isPortAvailable(30000);
```

### occupyPort

Occupies an available TCP port until `close()` is called. The host defaults to `0.0.0.0`.

```ts
import { occupyPort } from '@rstackjs/test-utils';

const { port, close } = await occupyPort();
try {
// Test behavior when this port is occupied.
} finally {
await close();
}
```

### proxyConsole

Captures console output and removes ANSI control characters. By default, it captures `log`, `warn`, `info`, and `error`.
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export { getDistFiles } from './getDistFiles.js';
export { getFileContent } from './getFileContent.js';
export { getRandomPort, isPortAvailable } from './getRandomPort.js';
export { normalizeEol } from './normalizeEol.js';
export { occupyPort } from './occupyPort.js';
export { prepareDist } from './prepareDist.js';
export {
type ConsoleType,
Expand Down
24 changes: 24 additions & 0 deletions src/occupyPort.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { once } from 'node:events';
import net from 'node:net';

/** Occupy an available TCP port until close() is called. */
export const occupyPort = async (host = '0.0.0.0') => {
const server = net.createServer().listen({ port: 0, host });
Comment thread
chenjiahan marked this conversation as resolved.
await once(server, 'listening');

const { port } = server.address() as net.AddressInfo;

return {
port,
close: () =>
new Promise<void>((resolve, reject) => {
server.close((error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
}),
};
};
26 changes: 26 additions & 0 deletions tests/occupyPort.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { once } from 'node:events';
import net from 'node:net';
import { expect, test } from 'rstack/test';
import { occupyPort } from '../src/index';

test('should occupy a port and release it when closed', async () => {
const { port, close } = await occupyPort();
const server = net.createServer();
const options = { port, host: '0.0.0.0' };

try {
try {
server.listen(options);
await expect(once(server, 'listening')).rejects.toMatchObject({
code: 'EADDRINUSE',
});
} finally {
await close();
}

server.listen(options);
await once(server, 'listening');
} finally {
await new Promise<void>((resolve) => server.close(() => resolve()));
}
});