mirror of
https://github.com/nestjs/nest.git
synced 2026-02-24 00:02:56 +00:00
Compare commits
277 Commits
v11.1.11
...
sample/esm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b28012ebf9 | ||
|
|
a21fd1d83a | ||
|
|
90a40d540e | ||
|
|
d2fd2e692e | ||
|
|
b6cecd81c4 | ||
|
|
9d4c8656cd | ||
|
|
fb3ae67e25 | ||
|
|
543142d5ce | ||
|
|
09c81568f8 | ||
|
|
473810cc85 | ||
|
|
50f0f7286c | ||
|
|
6586c0d985 | ||
|
|
df1537f74e | ||
|
|
62908b4a8b | ||
|
|
1c046aeea7 | ||
|
|
288453fabb | ||
|
|
6846cd7128 | ||
|
|
33f37d6270 | ||
|
|
fa6d45da74 | ||
|
|
1c324622de | ||
|
|
88a2c1c8bf | ||
|
|
829d326727 | ||
|
|
f854f9cbe6 | ||
|
|
af9b46513b | ||
|
|
b290fbc85f | ||
|
|
3c00b44771 | ||
|
|
fcaa117e22 | ||
|
|
35a1ec1adb | ||
|
|
d35b3a8fe8 | ||
|
|
7b9f885262 | ||
|
|
e50e3e79fb | ||
|
|
7cbebba3d8 | ||
|
|
770c7ca4af | ||
|
|
8b616d2e27 | ||
|
|
a2db2bc673 | ||
|
|
e7d186d605 | ||
|
|
ecd34f65c1 | ||
|
|
af11a1cdcf | ||
|
|
0fe64923ab | ||
|
|
5058600ae3 | ||
|
|
be35bb7dac | ||
|
|
ca64b40164 | ||
|
|
fa9baa8eb0 | ||
|
|
31c34340c6 | ||
|
|
91212b20d3 | ||
|
|
804d27bbe4 | ||
|
|
f66414667f | ||
|
|
b813820611 | ||
|
|
bec4329be4 | ||
|
|
5a42e7cf23 | ||
|
|
deb4c250a5 | ||
|
|
379f9f9030 | ||
|
|
ce86b45d7d | ||
|
|
2e75afa512 | ||
|
|
2bec40a801 | ||
|
|
8a8833d678 | ||
|
|
b0f5509f53 | ||
|
|
72be027d16 | ||
|
|
72283cc7a9 | ||
|
|
bb8cf85bc9 | ||
|
|
d0f4d7545b | ||
|
|
1b60fd317f | ||
|
|
8d1c16c1ca | ||
|
|
e3a958ac3e | ||
|
|
db90c3fb67 | ||
|
|
9a0ea3360c | ||
|
|
7bdca191c5 | ||
|
|
401d81b1c4 | ||
|
|
87cb6f92a5 | ||
|
|
a92bb399f9 | ||
|
|
3de4d8a8ef | ||
|
|
e9869ed2fa | ||
|
|
f5148709ff | ||
|
|
fad09363aa | ||
|
|
b885673aa8 | ||
|
|
fba0de79f2 | ||
|
|
346c954312 | ||
|
|
4081c1f5e0 | ||
|
|
1b11d01840 | ||
|
|
fcb774c8ed | ||
|
|
49cf11a063 | ||
|
|
bfa0ecb176 | ||
|
|
e5003a1a01 | ||
|
|
e4a19bbdeb | ||
|
|
e846bcd0e7 | ||
|
|
12e70a4bf4 | ||
|
|
8a0e32c616 | ||
|
|
007a9bdbe9 | ||
|
|
c96bb2a849 | ||
|
|
e49e92102a | ||
|
|
3cb3c2d6ad | ||
|
|
048da85025 | ||
|
|
3c7b75b00c | ||
|
|
2e8c645bc1 | ||
|
|
978256d75d | ||
|
|
d17dff12d4 | ||
|
|
a5be2710ee | ||
|
|
782e0715f0 | ||
|
|
91a9655d23 | ||
|
|
3a2b180ddb | ||
|
|
0d5b566789 | ||
|
|
6e8d083eed | ||
|
|
30ccfd75bd | ||
|
|
bd83c3f5eb | ||
|
|
7d8a4428a8 | ||
|
|
5dd0a9ab8c | ||
|
|
2c62817436 | ||
|
|
c818015862 | ||
|
|
321cf7dca2 | ||
|
|
db9494a2ad | ||
|
|
c875f6fb18 | ||
|
|
2748f48bfa | ||
|
|
ae495f7e82 | ||
|
|
4029607103 | ||
|
|
e2ef54b02b | ||
|
|
b4324b8968 | ||
|
|
d88856c3fa | ||
|
|
909b504d2d | ||
|
|
747de7149a | ||
|
|
84968c4dd8 | ||
|
|
a1f6162971 | ||
|
|
69892e4f95 | ||
|
|
faba27b355 | ||
|
|
ce37a4de1c | ||
|
|
58c761a10c | ||
|
|
ed8370697d | ||
|
|
a97228848c | ||
|
|
c5d8988f0e | ||
|
|
fd9607fd65 | ||
|
|
f6eb7317e2 | ||
|
|
1c1b017d9c | ||
|
|
69138113c5 | ||
|
|
7f70c1f992 | ||
|
|
db4779464a | ||
|
|
46a9190770 | ||
|
|
7ca537ad6d | ||
|
|
f507228dc7 | ||
|
|
d4e0c6fb40 | ||
|
|
3f8b278d53 | ||
|
|
82226347fd | ||
|
|
57129361dc | ||
|
|
c2944be1cf | ||
|
|
77b4b8a763 | ||
|
|
36e52495e0 | ||
|
|
9a97cbf0a4 | ||
|
|
8d528452ee | ||
|
|
3551745a48 | ||
|
|
3d1b44c0ca | ||
|
|
e94951f86b | ||
|
|
76b4fbed34 | ||
|
|
979a8e2f04 | ||
|
|
5535146f65 | ||
|
|
2fa655bbbf | ||
|
|
46ee1074f1 | ||
|
|
07022aff11 | ||
|
|
3459e9b595 | ||
|
|
e42362edb1 | ||
|
|
c78b7a1d67 | ||
|
|
9dd5d650d7 | ||
|
|
aca0658100 | ||
|
|
c93c247474 | ||
|
|
4fa9409366 | ||
|
|
2ab7ba377f | ||
|
|
8ccb55bddc | ||
|
|
b94858b4b1 | ||
|
|
2c95e3a159 | ||
|
|
fc682e4117 | ||
|
|
611bfc46cc | ||
|
|
c149138dc0 | ||
|
|
184757fbe3 | ||
|
|
36c064c255 | ||
|
|
9f2a48de3c | ||
|
|
b9e56c3978 | ||
|
|
b73328be85 | ||
|
|
b145994021 | ||
|
|
ffddbfe71e | ||
|
|
60df323ce0 | ||
|
|
df1f3af2cc | ||
|
|
8fb17f517c | ||
|
|
939559cd28 | ||
|
|
16296b9ce8 | ||
|
|
64ad1e263e | ||
|
|
96932ad073 | ||
|
|
09e96bdee7 | ||
|
|
4fdeb0b504 | ||
|
|
6620c431ea | ||
|
|
294506171f | ||
|
|
31fc72a90b | ||
|
|
e5616c2b92 | ||
|
|
5237c886d1 | ||
|
|
881bc371d6 | ||
|
|
2304a68250 | ||
|
|
defe683829 | ||
|
|
d9f1fea585 | ||
|
|
b79d89dd29 | ||
|
|
0c9e713f66 | ||
|
|
0aeab872c9 | ||
|
|
91ca1f913c | ||
|
|
52bb09abbf | ||
|
|
b41dd24259 | ||
|
|
a52e60820e | ||
|
|
c9de047945 | ||
|
|
caf8487b76 | ||
|
|
8501bb2c0b | ||
|
|
a830cedab9 | ||
|
|
841f150675 | ||
|
|
d3761bdb32 | ||
|
|
6f4da5c41e | ||
|
|
5f431b9f38 | ||
|
|
2526ec1f1a | ||
|
|
55b09b8387 | ||
|
|
29228ed9f4 | ||
|
|
85030eca5c | ||
|
|
15d1e4b103 | ||
|
|
373b78cfbb | ||
|
|
eea5c5899c | ||
|
|
87df305640 | ||
|
|
975e6099c2 | ||
|
|
014369029f | ||
|
|
0ae760071d | ||
|
|
31de8a1d2d | ||
|
|
4576270535 | ||
|
|
16a4d4d6a2 | ||
|
|
34d2103468 | ||
|
|
991d07267e | ||
|
|
a0cd0d543a | ||
|
|
a25170d8d6 | ||
|
|
af10902bcf | ||
|
|
30670319a8 | ||
|
|
8e6d6b7dfb | ||
|
|
9bcf7049c5 | ||
|
|
92a2ec2402 | ||
|
|
9415f659bd | ||
|
|
afefa9050e | ||
|
|
88af6c5428 | ||
|
|
72eec8964e | ||
|
|
22a5121d9c | ||
|
|
d2f3a2f7d6 | ||
|
|
6de4864790 | ||
|
|
02d2749b04 | ||
|
|
a9952edff0 | ||
|
|
23e13fb7c7 | ||
|
|
eac120336f | ||
|
|
45da564b8b | ||
|
|
3df5a1836c | ||
|
|
fb292791cf | ||
|
|
33911ead25 | ||
|
|
8a5be22e94 | ||
|
|
4500f04525 | ||
|
|
b1edd0872f | ||
|
|
73f71c45e8 | ||
|
|
936173ddff | ||
|
|
295bbe27f0 | ||
|
|
242e4cef4f | ||
|
|
01a14d46d1 | ||
|
|
fdfa52a2a7 | ||
|
|
f7d8e025d9 | ||
|
|
00f6e87586 | ||
|
|
112167837e | ||
|
|
da59d1c39c | ||
|
|
182f97d604 | ||
|
|
4869827aa0 | ||
|
|
8ead13d4f6 | ||
|
|
d021321624 | ||
|
|
66d5059b80 | ||
|
|
7a3f5b568f | ||
|
|
60355c44e0 | ||
|
|
38e4a826dc | ||
|
|
f40895423a | ||
|
|
ce83c9a6de | ||
|
|
b0aa22d030 | ||
|
|
2052855d3f | ||
|
|
d858df5dda | ||
|
|
91b97edfda | ||
|
|
00790a06ff | ||
|
|
1bbd3ec178 | ||
|
|
1818032838 |
@@ -1,12 +1,6 @@
|
||||
version: 2.1
|
||||
|
||||
parameters:
|
||||
check-legacy-node-version:
|
||||
type: boolean
|
||||
default: false
|
||||
legacy-node-version:
|
||||
type: string
|
||||
default: '18.20'
|
||||
maintenance-node-version:
|
||||
type: string
|
||||
default: '20.18'
|
||||
@@ -15,7 +9,7 @@ parameters:
|
||||
default: '22.11'
|
||||
current-node-version:
|
||||
type: string
|
||||
default: '23.3'
|
||||
default: '24.1'
|
||||
|
||||
aliases:
|
||||
- &restore-cache
|
||||
@@ -62,61 +56,36 @@ jobs:
|
||||
docker:
|
||||
- image: cimg/node:<< parameters.node-version >>
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
- *install-deps
|
||||
- *build-packages
|
||||
- when:
|
||||
condition:
|
||||
and:
|
||||
- equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.legacy-node-version >>',
|
||||
]
|
||||
- not: << pipeline.parameters.check-legacy-node-version >>
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
]
|
||||
steps:
|
||||
- run:
|
||||
name: Skip
|
||||
command: |
|
||||
echo Skipping
|
||||
name: Test (coverage)
|
||||
command: npm run test:cov
|
||||
- run:
|
||||
name: Collect coverage
|
||||
command: npm run coverage
|
||||
- store_artifacts:
|
||||
path: coverage
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
- not:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.legacy-node-version >>',
|
||||
]
|
||||
- << pipeline.parameters.check-legacy-node-version >>
|
||||
not:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
]
|
||||
steps:
|
||||
- checkout
|
||||
- *restore-cache
|
||||
- *install-deps
|
||||
- *build-packages
|
||||
- when:
|
||||
condition:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
]
|
||||
steps:
|
||||
- run:
|
||||
name: Test (coverage)
|
||||
command: npm run test:cov
|
||||
- run:
|
||||
name: Collect coverage
|
||||
command: npm run coverage
|
||||
- store_artifacts:
|
||||
path: coverage
|
||||
- when:
|
||||
condition:
|
||||
not:
|
||||
equal:
|
||||
[
|
||||
'<< parameters.node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
]
|
||||
steps:
|
||||
- *run-unit-tests
|
||||
- *run-unit-tests
|
||||
|
||||
lint:
|
||||
working_directory: ~/nest
|
||||
@@ -183,7 +152,6 @@ jobs:
|
||||
name: Build all samples
|
||||
command: npm run build:samples
|
||||
|
||||
|
||||
workflows:
|
||||
build-and-test:
|
||||
jobs:
|
||||
@@ -195,7 +163,6 @@ workflows:
|
||||
parameters:
|
||||
node-version:
|
||||
[
|
||||
'<< pipeline.parameters.legacy-node-version >>',
|
||||
'<< pipeline.parameters.maintenance-node-version >>',
|
||||
'<< pipeline.parameters.active-node-version >>',
|
||||
'<< pipeline.parameters.current-node-version >>',
|
||||
@@ -209,4 +176,3 @@ workflows:
|
||||
- samples:
|
||||
requires:
|
||||
- build
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# based on https://medium.com/@felipedutratine/intelligent-benchmark-with-wrk-163986c1587f
|
||||
|
||||
cd /tmp/
|
||||
sudo apt-get install build-essential libssl-dev git -y
|
||||
git clone --depth=1 https://github.com/wg/wrk.git wrk
|
||||
cd wrk
|
||||
sudo make
|
||||
# move the executable to somewhere in your PATH, ex:
|
||||
sudo cp wrk /usr/local/bin
|
||||
@@ -116,7 +116,6 @@ We cannot accept code without this.
|
||||
1. In GitHub, send a pull request to `nestjs:master`.
|
||||
|
||||
- If we suggest changes then:
|
||||
|
||||
- Make the required updates.
|
||||
- Re-run the Nest test suites to ensure tests are still passing.
|
||||
- Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
@@ -159,7 +158,7 @@ from the main (upstream) repository:
|
||||
|
||||
## <a name="development"></a> Development Setup
|
||||
|
||||
You will need [Node.js](https://nodejs.org) version >= 10.13.0 (except for v13).
|
||||
You will need [Node.js](https://nodejs.org) version >= 20.
|
||||
|
||||
1. After cloning the repo, run:
|
||||
|
||||
@@ -322,8 +321,10 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
||||
<!-- [coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md -->
|
||||
|
||||
[commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#
|
||||
|
||||
<!-- [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html -->
|
||||
<!-- [corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html -->
|
||||
|
||||
[dev-doc]: https://github.com/nestjs/nest/blob/master/docs/DEVELOPER.md
|
||||
[github]: https://github.com/nestjs/nest
|
||||
[stackoverflow]: https://stackoverflow.com/questions/tagged/nestjs
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2017-2025 Kamil Mysliwiec <https://kamilmysliwiec.com>
|
||||
Copyright (c) 2017-present Kamil Mysliwiec <https://kamilmysliwiec.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -63,6 +63,7 @@ Nest is an MIT-licensed open source project. It can grow thanks to the sponsors
|
||||
<td><a href="https://microsoft.com/" target="_blank"><img src="https://nestjs.com/img/logos/microsoft-logo.png" width="180" valign="middle" /></a></td>
|
||||
<td><a href="https://mojam.co" target="_blank"><img src="https://nestjs.com/img/logos/mojam-logo.png" width="80" valign="middle" /></a></td>
|
||||
<td><a href="https://valor-software.com/" target="_blank"><img src="https://docs.nestjs.com/assets/sponsors/valor-software.png" width="170" valign="middle" /></a></td>
|
||||
<td><a href="https://serpapi.com/" target="_blank"><img src="https://nestjs.com/img/logos/serpapi-logo.png" width="150" valign="middle" /></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
-----------------------
|
||||
express
|
||||
-----------------------
|
||||
Running 10s test @ http://localhost:3000
|
||||
1024 connections
|
||||
|
||||
┌─────────┬───────┬───────┬───────┬────────┬──────────┬──────────┬────────┐
|
||||
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
|
||||
├─────────┼───────┼───────┼───────┼────────┼──────────┼──────────┼────────┤
|
||||
│ Latency │ 55 ms │ 58 ms │ 91 ms │ 138 ms │ 61.88 ms │ 23.95 ms │ 747 ms │
|
||||
└─────────┴───────┴───────┴───────┴────────┴──────────┴──────────┴────────┘
|
||||
┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬─────────┬─────────┐
|
||||
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
|
||||
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
|
||||
│ Req/Sec │ 8407 │ 8407 │ 17407 │ 17743 │ 16454.41 │ 2716.94 │ 8402 │
|
||||
├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼─────────┼─────────┤
|
||||
│ Bytes/Sec │ 1.81 MB │ 1.81 MB │ 3.74 MB │ 3.81 MB │ 3.54 MB │ 584 kB │ 1.81 MB │
|
||||
└───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴─────────┴─────────┘
|
||||
|
||||
Req/Bytes counts sampled once per second.
|
||||
|
||||
165k requests in 10.17s, 35.4 MB read
|
||||
-----------------------
|
||||
nest (with "@nestjs/platform-express")
|
||||
-----------------------
|
||||
Running 10s test @ http://localhost:3000
|
||||
1024 connections
|
||||
|
||||
┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
|
||||
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
|
||||
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
|
||||
│ Latency │ 61 ms │ 64 ms │ 71 ms │ 94 ms │ 65.44 ms │ 17.35 ms │ 325 ms │
|
||||
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
|
||||
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┐
|
||||
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
|
||||
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
|
||||
│ Req/Sec │ 14183 │ 14183 │ 15767 │ 15991 │ 15640 │ 501.13 │ 14182 │
|
||||
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼────────┼─────────┤
|
||||
│ Bytes/Sec │ 3.06 MB │ 3.06 MB │ 3.41 MB │ 3.45 MB │ 3.38 MB │ 108 kB │ 3.06 MB │
|
||||
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┘
|
||||
|
||||
Req/Bytes counts sampled once per second.
|
||||
|
||||
156k requests in 10.24s, 33.8 MB read
|
||||
-----------------------
|
||||
fastify
|
||||
-----------------------
|
||||
Running 10s test @ http://localhost:3000
|
||||
1024 connections
|
||||
|
||||
┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬─────────┐
|
||||
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
|
||||
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼─────────┤
|
||||
│ Latency │ 27 ms │ 30 ms │ 39 ms │ 78 ms │ 31.62 ms │ 26.59 ms │ 1232 ms │
|
||||
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴─────────┘
|
||||
┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
|
||||
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
|
||||
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
|
||||
│ Req/Sec │ 19935 │ 19935 │ 33247 │ 34111 │ 32030.4 │ 4103.84 │ 19931 │
|
||||
├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤
|
||||
│ Bytes/Sec │ 3.03 MB │ 3.03 MB │ 5.05 MB │ 5.19 MB │ 4.87 MB │ 624 kB │ 3.03 MB │
|
||||
└───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
|
||||
|
||||
Req/Bytes counts sampled once per second.
|
||||
|
||||
320k requests in 10.18s, 48.7 MB read
|
||||
-----------------------
|
||||
nest (with "@nestjs/platform-fastify")
|
||||
-----------------------
|
||||
Running 10s test @ http://localhost:3000
|
||||
1024 connections
|
||||
|
||||
┌─────────┬───────┬───────┬───────┬───────┬──────────┬──────────┬────────┐
|
||||
│ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │
|
||||
├─────────┼───────┼───────┼───────┼───────┼──────────┼──────────┼────────┤
|
||||
│ Latency │ 31 ms │ 33 ms │ 38 ms │ 52 ms │ 34.41 ms │ 11.73 ms │ 245 ms │
|
||||
└─────────┴───────┴───────┴───────┴───────┴──────────┴──────────┴────────┘
|
||||
┌───────────┬─────────┬─────────┬────────┬─────────┬─────────┬─────────┬─────────┐
|
||||
│ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │
|
||||
├───────────┼─────────┼─────────┼────────┼─────────┼─────────┼─────────┼─────────┤
|
||||
│ Req/Sec │ 24911 │ 24911 │ 30031 │ 30335 │ 29470.4 │ 1564.48 │ 24907 │
|
||||
├───────────┼─────────┼─────────┼────────┼─────────┼─────────┼─────────┼─────────┤
|
||||
│ Bytes/Sec │ 3.81 MB │ 3.81 MB │ 4.6 MB │ 4.64 MB │ 4.51 MB │ 239 kB │ 3.81 MB │
|
||||
└───────────┴─────────┴─────────┴────────┴─────────┴─────────┴─────────┴─────────┘
|
||||
|
||||
Req/Bytes counts sampled once per second.
|
||||
|
||||
295k requests in 10.17s, 45.1 MB read
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
|
||||
app.get('/', async (req, res) => res.send('Hello world'));
|
||||
app.listen(3000);
|
||||
@@ -1,7 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const fastify = require('fastify')();
|
||||
fastify.get('/', async (req, reply) => reply.send('Hello world'));
|
||||
fastify.listen({
|
||||
port: 3000
|
||||
});
|
||||
@@ -1,14 +0,0 @@
|
||||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
const core_1 = require('@nestjs/core');
|
||||
const fastify_platform_1 = require('@nestjs/platform-fastify');
|
||||
const app_module_1 = require('./nest/app.module');
|
||||
core_1.NestFactory.create(
|
||||
app_module_1.AppModule,
|
||||
new fastify_platform_1.FastifyAdapter(),
|
||||
{
|
||||
logger: false,
|
||||
bodyParser: false,
|
||||
},
|
||||
).then(app => app.listen(3000));
|
||||
//# sourceMappingURL=main.js.map
|
||||
@@ -1,9 +0,0 @@
|
||||
'use strict';
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
const core_1 = require('@nestjs/core');
|
||||
const app_module_1 = require('./nest/app.module');
|
||||
core_1.NestFactory.create(app_module_1.AppModule, {
|
||||
logger: false,
|
||||
bodyParser: false,
|
||||
}).then(app => app.listen(3000));
|
||||
//# sourceMappingURL=main.js.map
|
||||
3
benchmarks/nest/app.controller.d.ts
vendored
3
benchmarks/nest/app.controller.d.ts
vendored
@@ -1,3 +0,0 @@
|
||||
export declare class AppController {
|
||||
root(): string;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
'use strict';
|
||||
var __decorate =
|
||||
(this && this.__decorate) ||
|
||||
function(decorators, target, key, desc) {
|
||||
var c = arguments.length,
|
||||
r =
|
||||
c < 3
|
||||
? target
|
||||
: desc === null
|
||||
? (desc = Object.getOwnPropertyDescriptor(target, key))
|
||||
: desc,
|
||||
d;
|
||||
if (typeof Reflect === 'object' && typeof Reflect.decorate === 'function')
|
||||
r = Reflect.decorate(decorators, target, key, desc);
|
||||
else
|
||||
for (var i = decorators.length - 1; i >= 0; i--)
|
||||
if ((d = decorators[i]))
|
||||
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata =
|
||||
(this && this.__metadata) ||
|
||||
function(k, v) {
|
||||
if (typeof Reflect === 'object' && typeof Reflect.metadata === 'function')
|
||||
return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
const common_1 = require('@nestjs/common');
|
||||
let AppController = class AppController {
|
||||
root() {
|
||||
return 'Hello world!';
|
||||
}
|
||||
};
|
||||
__decorate(
|
||||
[
|
||||
common_1.Get(),
|
||||
__metadata('design:type', Function),
|
||||
__metadata('design:paramtypes', []),
|
||||
__metadata('design:returntype', String),
|
||||
],
|
||||
AppController.prototype,
|
||||
'root',
|
||||
null,
|
||||
);
|
||||
AppController = __decorate([common_1.Controller()], AppController);
|
||||
exports.AppController = AppController;
|
||||
//# sourceMappingURL=app.controller.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,2CAAiD;AAGjD,IAAa,aAAa,GAA1B,MAAa,aAAa;IAExB,IAAI;QACF,OAAO,cAAc,CAAA;IACvB,CAAC;CACF,CAAA;AAHC;IADC,YAAG,EAAE;;;;yCAGL;AAJU,aAAa;IADzB,mBAAU,EAAE;GACA,aAAa,CAKzB;AALY,sCAAa"}
|
||||
1
benchmarks/nest/app.module.d.ts
vendored
1
benchmarks/nest/app.module.d.ts
vendored
@@ -1 +0,0 @@
|
||||
export declare class AppModule {}
|
||||
@@ -1,20 +0,0 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const common_1 = require("@nestjs/common");
|
||||
const app_controller_1 = require("./app.controller");
|
||||
let AppModule = class AppModule {
|
||||
};
|
||||
AppModule = __decorate([
|
||||
common_1.Module({
|
||||
imports: [],
|
||||
controllers: [app_controller_1.AppController],
|
||||
})
|
||||
], AppModule);
|
||||
exports.AppModule = AppModule;
|
||||
//# sourceMappingURL=app.module.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;AAAA,2CAAwC;AACxC,qDAAiD;AAMjD,IAAa,SAAS,GAAtB,MAAa,SAAS;CAAG,CAAA;AAAZ,SAAS;IAJrB,eAAM,CAAC;QACN,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,CAAC,8BAAa,CAAC;KAC7B,CAAC;GACW,SAAS,CAAG;AAAZ,8BAAS"}
|
||||
1
benchmarks/nest/main.d.ts
vendored
1
benchmarks/nest/main.d.ts
vendored
@@ -1 +0,0 @@
|
||||
export {};
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAChD,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AACD,SAAS,EAAE,CAAC"}
|
||||
@@ -38,18 +38,18 @@ export default tseslint.config(
|
||||
'@typescript-eslint/no-require-imports': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'warn',
|
||||
"@typescript-eslint/no-misused-promises": [
|
||||
"error",
|
||||
'@typescript-eslint/no-misused-promises': [
|
||||
'error',
|
||||
{
|
||||
"checksVoidReturn": false,
|
||||
"checksConditionals": false
|
||||
}
|
||||
checksVoidReturn: false,
|
||||
checksConditionals: false,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/require-await": "off",
|
||||
'@typescript-eslint/require-await': 'off',
|
||||
'@typescript-eslint/prefer-promise-reject-errors': 'off',
|
||||
'@typescript-eslint/no-base-to-string': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'@typescript-eslint/only-throw-error': 'off',
|
||||
},
|
||||
},
|
||||
);
|
||||
);
|
||||
|
||||
16
gulpfile.js
16
gulpfile.js
@@ -1,16 +0,0 @@
|
||||
'use strict';
|
||||
/**
|
||||
* Load the TypeScript compiler, then load the TypeScript gulpfile which simply loads all
|
||||
* the tasks. The tasks are really inside tools/gulp/tasks.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const projectDir = __dirname;
|
||||
const tsconfigPath = path.join(projectDir, 'tools/gulp/tsconfig.json');
|
||||
|
||||
require('ts-node').register({
|
||||
project: tsconfigPath
|
||||
});
|
||||
|
||||
require('./tools/gulp/gulpfile');
|
||||
13
gulpfile.mjs
Normal file
13
gulpfile.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Load the TypeScript compiler, then load the TypeScript gulpfile which simply loads all
|
||||
* the tasks. The tasks are really inside tools/gulp/tasks.
|
||||
*/
|
||||
|
||||
import { register } from 'node:module';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
register('ts-node/esm', pathToFileURL('./'), {
|
||||
data: { project: './tools/gulp/tsconfig.json' },
|
||||
});
|
||||
|
||||
await import('./tools/gulp/gulpfile.ts');
|
||||
@@ -1,7 +0,0 @@
|
||||
export const mochaHooks = (): Mocha.RootHookObject => {
|
||||
return {
|
||||
async beforeAll(this: Mocha.Context) {
|
||||
await import('reflect-metadata');
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { FooService } from './foo.service';
|
||||
import { FooService } from './foo.service.js';
|
||||
|
||||
@Injectable()
|
||||
export class BarService {
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as chai from 'chai';
|
||||
import * as chaiAsPromised from 'chai-as-promised';
|
||||
import * as sinon from 'sinon';
|
||||
import { BarService } from '../src/bar.service';
|
||||
import { FooService } from '../src/foo.service';
|
||||
|
||||
chai.use(chaiAsPromised);
|
||||
const { expect } = chai;
|
||||
import { BarService } from '../src/bar.service.js';
|
||||
import { FooService } from '../src/foo.service.js';
|
||||
|
||||
describe('Auto-Mocking Bar Deps', () => {
|
||||
let service: BarService;
|
||||
let fooService: FooService;
|
||||
const stub = sinon.stub();
|
||||
const stub = vi.fn();
|
||||
beforeEach(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
providers: [BarService],
|
||||
@@ -23,12 +17,12 @@ describe('Auto-Mocking Bar Deps', () => {
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).not.to.be.undefined;
|
||||
expect(fooService).not.to.be.undefined;
|
||||
expect(service).not.toBeUndefined();
|
||||
expect(fooService).not.toBeUndefined();
|
||||
});
|
||||
it('should call bar.bar', () => {
|
||||
service.bar();
|
||||
expect(stub.called);
|
||||
expect(stub).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,23 +33,25 @@ describe('Auto-Mocking with token in factory', () => {
|
||||
})
|
||||
.useMocker(token => {
|
||||
if (token === FooService) {
|
||||
return { foo: sinon.stub };
|
||||
return { foo: vi.fn() };
|
||||
}
|
||||
})
|
||||
.compile();
|
||||
const service = moduleRef.get(BarService);
|
||||
const fooServ = moduleRef.get<{ foo: sinon.SinonStub }>(FooService as any);
|
||||
const fooServ = moduleRef.get<{ foo: ReturnType<typeof vi.fn> }>(
|
||||
FooService as any,
|
||||
);
|
||||
service.bar();
|
||||
expect(fooServ.foo.called);
|
||||
expect(fooServ.foo).toHaveBeenCalled();
|
||||
});
|
||||
it('cannot mock the dependencies', async () => {
|
||||
const moduleRef = Test.createTestingModule({
|
||||
providers: [BarService],
|
||||
}).useMocker(token => {
|
||||
if (token === FooService.name + 'something that fails the token') {
|
||||
return { foo: sinon.stub };
|
||||
return { foo: vi.fn() };
|
||||
}
|
||||
}).compile;
|
||||
expect(moduleRef()).to.eventually.throw();
|
||||
await expect(moduleRef()).rejects.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Express Cors', () => {
|
||||
let app: NestExpressApplication;
|
||||
@@ -25,7 +25,7 @@ describe('Express Cors', () => {
|
||||
];
|
||||
describe('Dynamic config', () => {
|
||||
describe('enableCors', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -66,13 +66,13 @@ describe('Express Cors', () => {
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Application Options', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -114,14 +114,14 @@ describe('Express Cors', () => {
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('Static config', () => {
|
||||
describe('enableCors', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -141,14 +141,14 @@ describe('Express Cors', () => {
|
||||
.expect('access-control-expose-headers', 'foo,bar')
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Application Options', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -169,7 +169,7 @@ describe('Express Cors', () => {
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,8 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe.skip('Fastify Cors', () => {
|
||||
let app: NestFastifyApplication;
|
||||
@@ -28,7 +28,7 @@ describe.skip('Fastify Cors', () => {
|
||||
];
|
||||
describe('Dynamic config', () => {
|
||||
describe('enableCors', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -73,13 +73,13 @@ describe.skip('Fastify Cors', () => {
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Application Options', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -124,7 +124,7 @@ describe.skip('Fastify Cors', () => {
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
@@ -132,7 +132,7 @@ describe.skip('Fastify Cors', () => {
|
||||
|
||||
describe('Static config', () => {
|
||||
describe('enableCors', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -154,14 +154,14 @@ describe.skip('Fastify Cors', () => {
|
||||
.expect('access-control-expose-headers', 'foo,bar')
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Application Options', () => {
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
}).compile();
|
||||
@@ -184,10 +184,10 @@ describe.skip('Fastify Cors', () => {
|
||||
.expect('access-control-expose-headers', 'foo,bar')
|
||||
.expect('content-length', '0');
|
||||
});
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await app.close();
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppController } from './app.controller.js';
|
||||
|
||||
@Module({
|
||||
controllers: [AppController],
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { DiscoveryService } from '@nestjs/core';
|
||||
import { expect } from 'chai';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { WebhooksExplorer } from '../src/webhooks.explorer';
|
||||
import { NonAppliedDecorator } from '../src/decorators/non-applied.decorator';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
import { NonAppliedDecorator } from '../src/decorators/non-applied.decorator.js';
|
||||
import { WebhooksExplorer } from '../src/webhooks.explorer.js';
|
||||
|
||||
describe('DiscoveryModule', () => {
|
||||
let moduleRef: TestingModule;
|
||||
@@ -14,10 +13,14 @@ describe('DiscoveryModule', () => {
|
||||
}).compile();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await moduleRef.close();
|
||||
});
|
||||
|
||||
it('should discover all providers & handlers with corresponding annotations', async () => {
|
||||
const webhooksExplorer = moduleRef.get(WebhooksExplorer);
|
||||
|
||||
expect(webhooksExplorer.getWebhooks()).to.be.eql([
|
||||
expect(webhooksExplorer.getWebhooks()).toEqual([
|
||||
{
|
||||
handlers: [
|
||||
{
|
||||
@@ -45,7 +48,7 @@ describe('DiscoveryModule', () => {
|
||||
const providers = discoveryService.getProviders({
|
||||
metadataKey: NonAppliedDecorator.KEY,
|
||||
});
|
||||
expect(providers).to.be.eql([]);
|
||||
expect(providers).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return an empty array if no controllers were found for a given discoverable decorator', () => {
|
||||
@@ -54,6 +57,6 @@ describe('DiscoveryModule', () => {
|
||||
const controllers = discoveryService.getControllers({
|
||||
metadataKey: NonAppliedDecorator.KEY,
|
||||
});
|
||||
expect(controllers).to.be.eql([]);
|
||||
expect(controllers).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DiscoveryModule } from '@nestjs/core';
|
||||
import { MyWebhookModule } from './my-webhook/my-webhook.module';
|
||||
import { WebhooksExplorer } from './webhooks.explorer';
|
||||
import { MyWebhookModule } from './my-webhook/my-webhook.module.js';
|
||||
import { WebhooksExplorer } from './webhooks.explorer.js';
|
||||
|
||||
@Module({
|
||||
imports: [MyWebhookModule, DiscoveryModule],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Webhook, WebhookHandler } from '../decorators/webhook.decorators';
|
||||
import { Webhook, WebhookHandler } from '../decorators/webhook.decorators.js';
|
||||
|
||||
@Webhook({ name: 'cleanup' })
|
||||
export class CleanupWebhook {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Webhook, WebhookHandler } from '../decorators/webhook.decorators';
|
||||
import { Webhook, WebhookHandler } from '../decorators/webhook.decorators.js';
|
||||
|
||||
@Webhook({ name: 'flush' })
|
||||
export class FlushWebhook {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CleanupWebhook } from './cleanup.webhook';
|
||||
import { FlushWebhook } from './flush.webhook';
|
||||
import { CleanupWebhook } from './cleanup.webhook.js';
|
||||
import { FlushWebhook } from './flush.webhook.js';
|
||||
|
||||
@Module({ providers: [CleanupWebhook, FlushWebhook] })
|
||||
export class MyWebhookModule {}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DiscoveryService, MetadataScanner } from '@nestjs/core';
|
||||
import { Webhook, WebhookHandler } from './decorators/webhook.decorators';
|
||||
import { Webhook, WebhookHandler } from './decorators/webhook.decorators.js';
|
||||
|
||||
@Injectable()
|
||||
export class WebhooksExplorer {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- "9001:9001"
|
||||
restart: always
|
||||
mysql:
|
||||
image: mysql:9.5.0
|
||||
image: mysql:9.6.0
|
||||
environment:
|
||||
MYSQL_ROOT_HOST: '%'
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('GraphQL - Code-first', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('GraphQL - Guards', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication, ValidationPipe } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('GraphQL Pipes', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { join } from 'path';
|
||||
import { RecipesModule } from './recipes/recipes.module';
|
||||
import { RecipesModule } from './recipes/recipes.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ValidationPipe } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { AppModule } from './app.module.js';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { APP_FILTER } from '@nestjs/core';
|
||||
import { UnauthorizedFilter } from '../common/filters/unauthorized.filter';
|
||||
import { DateScalar } from '../common/scalars/date.scalar';
|
||||
import { RecipesResolver } from './recipes.resolver';
|
||||
import { RecipesService } from './recipes.service';
|
||||
import { UnauthorizedFilter } from '../common/filters/unauthorized.filter.js';
|
||||
import { DateScalar } from '../common/scalars/date.scalar.js';
|
||||
import { RecipesResolver } from './recipes.resolver.js';
|
||||
import { RecipesService } from './recipes.service.js';
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { NotFoundException, UseGuards, UseInterceptors } from '@nestjs/common';
|
||||
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
import { AuthGuard } from '../common/guards/auth.guard';
|
||||
import { DataInterceptor } from '../common/interceptors/data.interceptor';
|
||||
import { NewRecipeInput } from './dto/new-recipe.input';
|
||||
import { RecipesArgs } from './dto/recipes.args';
|
||||
import { Recipe } from './models/recipe';
|
||||
import { RecipesService } from './recipes.service';
|
||||
import { AuthGuard } from '../common/guards/auth.guard.js';
|
||||
import { DataInterceptor } from '../common/interceptors/data.interceptor.js';
|
||||
import { NewRecipeInput } from './dto/new-recipe.input.js';
|
||||
import { RecipesArgs } from './dto/recipes.args.js';
|
||||
import { Recipe } from './models/recipe.js';
|
||||
import { RecipesService } from './recipes.service.js';
|
||||
|
||||
const pubSub = new PubSub();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { NewRecipeInput } from './dto/new-recipe.input';
|
||||
import { RecipesArgs } from './dto/recipes.args';
|
||||
import { Recipe } from './models/recipe';
|
||||
import { NewRecipeInput } from './dto/new-recipe.input.js';
|
||||
import { RecipesArgs } from './dto/recipes.args.js';
|
||||
import { Recipe } from './models/recipe.js';
|
||||
|
||||
@Injectable()
|
||||
export class RecipesService {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import * as request from 'supertest';
|
||||
import { AsyncClassApplicationModule } from '../src/async-options-class.module';
|
||||
import request from 'supertest';
|
||||
import { AsyncClassApplicationModule } from '../src/async-options-class.module.js';
|
||||
|
||||
describe('GraphQL (async class)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import * as request from 'supertest';
|
||||
import { AsyncExistingApplicationModule } from '../src/async-options-existing.module';
|
||||
import request from 'supertest';
|
||||
import { AsyncExistingApplicationModule } from '../src/async-options-existing.module.js';
|
||||
|
||||
describe('GraphQL (async existing)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import * as request from 'supertest';
|
||||
import { AsyncApplicationModule } from '../src/async-options.module';
|
||||
import request from 'supertest';
|
||||
import { AsyncApplicationModule } from '../src/async-options.module.js';
|
||||
|
||||
describe('GraphQL (async configuration)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -2,11 +2,10 @@ import { ApolloDriver } from '@nestjs/apollo';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { join } from 'path';
|
||||
import * as request from 'supertest';
|
||||
import { CatsRequestScopedService } from '../src/cats/cats-request-scoped.service';
|
||||
import { CatsModule } from '../src/cats/cats.module';
|
||||
import request from 'supertest';
|
||||
import { CatsRequestScopedService } from '../src/cats/cats-request-scoped.service.js';
|
||||
import { CatsModule } from '../src/cats/cats.module.js';
|
||||
|
||||
describe('GraphQL request scoped', () => {
|
||||
let app: INestApplication;
|
||||
@@ -17,7 +16,9 @@ describe('GraphQL request scoped', () => {
|
||||
CatsModule.enableRequestScope(),
|
||||
GraphQLModule.forRoot({
|
||||
driver: ApolloDriver,
|
||||
typePaths: [join(__dirname, '..', 'src', '**', '*.graphql')],
|
||||
typePaths: [
|
||||
join(import.meta.dirname, '..', 'src', '**', '*.graphql'),
|
||||
],
|
||||
}),
|
||||
],
|
||||
}).compile();
|
||||
@@ -53,7 +54,7 @@ describe('GraphQL request scoped', () => {
|
||||
});
|
||||
|
||||
it(`should create resolver for each incoming request`, () => {
|
||||
expect(CatsRequestScopedService.COUNTER).to.be.eql(3);
|
||||
expect(CatsRequestScopedService.COUNTER).toEqual(3);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('GraphQL', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { join } from 'path';
|
||||
import { CatsModule } from './cats/cats.module';
|
||||
import { CatsModule } from './cats/cats.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -10,7 +10,7 @@ import { CatsModule } from './cats/cats.module';
|
||||
GraphQLModule.forRoot<ApolloDriverConfig>({
|
||||
driver: ApolloDriver,
|
||||
includeStacktraceInErrorResponses: true,
|
||||
typePaths: [join(__dirname, '**', '*.graphql')],
|
||||
typePaths: [join(import.meta.dirname, '**', '*.graphql')],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -2,12 +2,12 @@ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GqlOptionsFactory, GraphQLModule } from '@nestjs/graphql';
|
||||
import { join } from 'path';
|
||||
import { CatsModule } from './cats/cats.module';
|
||||
import { CatsModule } from './cats/cats.module.js';
|
||||
|
||||
class ConfigService implements GqlOptionsFactory {
|
||||
createGqlOptions(): ApolloDriverConfig {
|
||||
return {
|
||||
typePaths: [join(__dirname, '**', '*.graphql')],
|
||||
typePaths: [join(import.meta.dirname, '**', '*.graphql')],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { CatsModule } from './cats/cats.module';
|
||||
import { ConfigModule } from './config.module';
|
||||
import { ConfigService } from './config.service';
|
||||
import { CatsModule } from './cats/cats.module.js';
|
||||
import { ConfigModule } from './config.module.js';
|
||||
import { ConfigService } from './config.service.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { GraphQLModule } from '@nestjs/graphql';
|
||||
import { join } from 'path';
|
||||
import { CatsModule } from './cats/cats.module';
|
||||
import { CatsModule } from './cats/cats.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -10,7 +10,7 @@ import { CatsModule } from './cats/cats.module';
|
||||
GraphQLModule.forRootAsync<ApolloDriverConfig>({
|
||||
driver: ApolloDriver,
|
||||
useFactory: async () => ({
|
||||
typePaths: [join(__dirname, '**', '*.graphql')],
|
||||
typePaths: [join(import.meta.dirname, '**', '*.graphql')],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable, Scope } from '@nestjs/common';
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
import { Cat } from './interfaces/cat.interface.js';
|
||||
|
||||
@Injectable({ scope: Scope.REQUEST })
|
||||
export class CatsRequestScopedService {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DynamicModule, Module, Scope } from '@nestjs/common';
|
||||
import { CatsRequestScopedService } from './cats-request-scoped.service';
|
||||
import { CatsResolvers } from './cats.resolvers';
|
||||
import { CatsService } from './cats.service';
|
||||
import { CatsRequestScopedService } from './cats-request-scoped.service.js';
|
||||
import { CatsResolvers } from './cats.resolvers.js';
|
||||
import { CatsService } from './cats.service.js';
|
||||
|
||||
@Module({
|
||||
providers: [CatsService, CatsResolvers],
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ParseIntPipe, UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
|
||||
import { PubSub } from 'graphql-subscriptions';
|
||||
import { CatsGuard } from './cats.guard';
|
||||
import { CatsService } from './cats.service';
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
import { CatsGuard } from './cats.guard.js';
|
||||
import { CatsService } from './cats.service.js';
|
||||
import { Cat } from './interfaces/cat.interface.js';
|
||||
|
||||
const pubSub = new PubSub();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Cat } from './interfaces/cat.interface';
|
||||
import { Cat } from './interfaces/cat.interface.js';
|
||||
|
||||
@Injectable()
|
||||
export class CatsService {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigService } from './config.service';
|
||||
import { ConfigService } from './config.service.js';
|
||||
|
||||
@Module({
|
||||
providers: [ConfigService],
|
||||
|
||||
@@ -6,7 +6,7 @@ import { join } from 'path';
|
||||
export class ConfigService implements GqlOptionsFactory {
|
||||
createGqlOptions(): GqlModuleOptions {
|
||||
return {
|
||||
typePaths: [join(__dirname, '**', '*.graphql')],
|
||||
typePaths: [join(import.meta.dirname, '**', '*.graphql')],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { AppModule } from './app.module';
|
||||
import { AppModule } from './app.module.js';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
@@ -4,10 +4,9 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { RawServerDefault } from 'fastify';
|
||||
import * as request from 'supertest';
|
||||
import { ErrorsController } from '../src/errors/errors.controller';
|
||||
import request from 'supertest';
|
||||
import { ErrorsController } from '../src/errors/errors.controller.js';
|
||||
|
||||
describe('Error messages', () => {
|
||||
let server: RawServerDefault;
|
||||
@@ -82,14 +81,12 @@ describe('Error messages', () => {
|
||||
url: '/sync',
|
||||
})
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).to.equal(HttpStatus.BAD_REQUEST);
|
||||
expect(payload).to.equal(
|
||||
JSON.stringify({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'Integration test',
|
||||
}),
|
||||
);
|
||||
expect(statusCode).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(JSON.parse(payload)).toEqual({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'Integration test',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -97,17 +94,15 @@ describe('Error messages', () => {
|
||||
return app
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/sync',
|
||||
url: '/async',
|
||||
})
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).to.equal(HttpStatus.BAD_REQUEST);
|
||||
expect(payload).to.equal(
|
||||
JSON.stringify({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'Integration test',
|
||||
}),
|
||||
);
|
||||
expect(statusCode).toBe(HttpStatus.BAD_REQUEST);
|
||||
expect(JSON.parse(payload)).toEqual({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'Integration test',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -118,13 +113,11 @@ describe('Error messages', () => {
|
||||
url: '/unexpected-error',
|
||||
})
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).to.equal(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(payload).to.equal(
|
||||
JSON.stringify({
|
||||
statusCode: 500,
|
||||
message: 'Internal server error',
|
||||
}),
|
||||
);
|
||||
expect(statusCode).toBe(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(JSON.parse(payload)).toEqual({
|
||||
statusCode: 500,
|
||||
message: 'Internal server error',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const RETURN_VALUE = 'test';
|
||||
const MIDDLEWARE_VALUE = 'middleware';
|
||||
|
||||
@@ -8,8 +8,8 @@ import {
|
||||
RequestMethod,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const RETURN_VALUE = 'test';
|
||||
const MIDDLEWARE_VALUE = 'middleware';
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { ExpressAdapter } from '@nestjs/platform-express';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as express from 'express';
|
||||
import * as request from 'supertest';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { App } from 'supertest/types';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Hello world (express instance)', () => {
|
||||
let server: App;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { ExpressAdapter } from '@nestjs/platform-express';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as express from 'express';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import express from 'express';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Hello world (express instance with multiple applications)', () => {
|
||||
let server;
|
||||
|
||||
@@ -3,8 +3,7 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Hello world (fastify adapter)', () => {
|
||||
let app: NestFastifyApplication;
|
||||
@@ -26,7 +25,10 @@ describe('Hello world (fastify adapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).toBe(200);
|
||||
expect(payload).toEqual('Hello world!');
|
||||
});
|
||||
});
|
||||
|
||||
it(`/GET (Promise/async)`, () => {
|
||||
@@ -35,7 +37,10 @@ describe('Hello world (fastify adapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/hello/async',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).toBe(200);
|
||||
expect(payload).toEqual('Hello world!');
|
||||
});
|
||||
});
|
||||
|
||||
it(`/GET (Observable stream)`, () => {
|
||||
@@ -44,7 +49,10 @@ describe('Hello world (fastify adapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/hello/stream',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).toBe(200);
|
||||
expect(payload).toEqual('Hello world!');
|
||||
});
|
||||
});
|
||||
|
||||
it(`/GET { host: ":tenant.example.com" } not matched`, () => {
|
||||
@@ -54,7 +62,7 @@ describe('Hello world (fastify adapter)', () => {
|
||||
url: '/host',
|
||||
})
|
||||
.then(({ payload }) => {
|
||||
expect(JSON.parse(payload)).to.be.eql({
|
||||
expect(JSON.parse(payload)).toEqual({
|
||||
error: 'Internal Server Error',
|
||||
message:
|
||||
'HTTP adapter does not support filtering on host: ":tenant.example.com"',
|
||||
@@ -70,7 +78,7 @@ describe('Hello world (fastify adapter)', () => {
|
||||
url: '/host-array',
|
||||
})
|
||||
.then(({ payload }) => {
|
||||
expect(JSON.parse(payload)).to.be.eql({
|
||||
expect(JSON.parse(payload)).toEqual({
|
||||
error: 'Internal Server Error',
|
||||
message:
|
||||
'HTTP adapter does not support filtering on hosts: [":tenant.example1.com", ":tenant.example2.com"]',
|
||||
@@ -84,7 +92,10 @@ describe('Hello world (fastify adapter)', () => {
|
||||
.inject()
|
||||
.get('/hello')
|
||||
.end()
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
.then(({ payload, statusCode }) => {
|
||||
expect(statusCode).toBe(200);
|
||||
expect(payload).toEqual('Hello world!');
|
||||
});
|
||||
});
|
||||
|
||||
it('/HEAD should respond to with a 200', () => {
|
||||
@@ -93,7 +104,7 @@ describe('Hello world (fastify adapter)', () => {
|
||||
method: 'HEAD',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ statusCode }) => expect(statusCode).to.be.eq(200));
|
||||
.then(({ statusCode }) => expect(statusCode).toBe(200));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
|
||||
describe('Middleware before init (FastifyAdapter)', () => {
|
||||
let app: NestFastifyApplication;
|
||||
@@ -81,11 +80,11 @@ describe('Middleware before init (FastifyAdapter)', () => {
|
||||
url: '/test',
|
||||
})
|
||||
.then(({ statusCode, payload, headers }) => {
|
||||
expect(statusCode).to.equal(200);
|
||||
expect(JSON.parse(payload)).to.deep.equal({ data: 'test_data' });
|
||||
expect(statusCode).toBe(200);
|
||||
expect(JSON.parse(payload)).toEqual({ data: 'test_data' });
|
||||
// Verify both module-level and global middleware were applied
|
||||
expect(headers['x-middleware']).to.equal('applied');
|
||||
expect(headers['x-global-middleware']).to.equal('applied');
|
||||
expect(headers['x-middleware']).toBe('applied');
|
||||
expect(headers['x-global-middleware']).toBe('applied');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,8 +122,8 @@ describe('Middleware before init (FastifyAdapter)', () => {
|
||||
url: '/test',
|
||||
})
|
||||
.then(({ statusCode, payload }) => {
|
||||
expect(statusCode).to.equal(200);
|
||||
expect(JSON.parse(payload)).to.deep.equal({ data: 'test_data' });
|
||||
expect(statusCode).toBe(200);
|
||||
expect(JSON.parse(payload)).toEqual({ data: 'test_data' });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,91 +1,4 @@
|
||||
/* Temporarily disabled due to various regressions
|
||||
|
||||
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { ApplicationModule } from '../src/app.module';
|
||||
|
||||
describe('Hello world (fastify adapter with multiple applications)', () => {
|
||||
let adapter: FastifyAdapter;
|
||||
let apps: NestFastifyApplication[];
|
||||
|
||||
beforeEach(async () => {
|
||||
const module1 = await Test.createTestingModule({
|
||||
imports: [ApplicationModule],
|
||||
}).compile();
|
||||
const module2 = await Test.createTestingModule({
|
||||
imports: [ApplicationModule],
|
||||
}).compile();
|
||||
|
||||
adapter = new FastifyAdapter();
|
||||
|
||||
apps = [
|
||||
module1.createNestApplication<NestFastifyApplication>(adapter),
|
||||
module2
|
||||
.createNestApplication<NestFastifyApplication>(adapter, {
|
||||
bodyParser: false,
|
||||
})
|
||||
.setGlobalPrefix('/app2'),
|
||||
];
|
||||
await Promise.all(apps.map(app => app.init()));
|
||||
});
|
||||
|
||||
it(`/GET`, () => {
|
||||
return adapter
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
it(`/GET (app2)`, () => {
|
||||
return adapter
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/app2/hello',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
it(`/GET (Promise/async)`, () => {
|
||||
return adapter
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/hello/async',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
it(`/GET (app2 Promise/async)`, () => {
|
||||
return adapter
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/app2/hello/async',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
it(`/GET (Observable stream)`, () => {
|
||||
return adapter
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/hello/stream',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
it(`/GET (app2 Observable stream)`, () => {
|
||||
return adapter
|
||||
.inject({
|
||||
method: 'GET',
|
||||
url: '/app2/hello/stream',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql('Hello world!'));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(apps.map(app => app.close()));
|
||||
await adapter.close();
|
||||
});
|
||||
});*/
|
||||
// Temporarily disabled due to various regressions
|
||||
describe.skip('Hello world (fastify adapter with multiple applications)', () => {
|
||||
it('placeholder', () => {});
|
||||
});
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
import { ConsoleLogger, INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import * as sinon from 'sinon';
|
||||
import { expect } from 'chai';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('ForceConsole Option', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
describe('When forceConsole is true', () => {
|
||||
let consoleLogSpy: sinon.SinonSpy;
|
||||
let consoleErrorSpy: sinon.SinonSpy;
|
||||
let processStdoutSpy: sinon.SinonSpy;
|
||||
let processStderrSpy: sinon.SinonSpy;
|
||||
let consoleLogSpy: ReturnType<typeof vi.fn>;
|
||||
let consoleErrorSpy: ReturnType<typeof vi.fn>;
|
||||
let processStdoutSpy: ReturnType<typeof vi.fn>;
|
||||
let processStderrSpy: ReturnType<typeof vi.fn>;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Spy on console and process methods
|
||||
consoleLogSpy = sinon.spy(console, 'log');
|
||||
consoleErrorSpy = sinon.spy(console, 'error');
|
||||
processStdoutSpy = sinon.spy(process.stdout, 'write');
|
||||
processStderrSpy = sinon.spy(process.stderr, 'write');
|
||||
consoleLogSpy = vi.spyOn(console, 'log');
|
||||
consoleErrorSpy = vi.spyOn(console, 'error');
|
||||
processStdoutSpy = vi.spyOn(process.stdout, 'write');
|
||||
processStderrSpy = vi.spyOn(process.stderr, 'write');
|
||||
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
@@ -34,10 +32,10 @@ describe('ForceConsole Option', () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
consoleLogSpy.restore();
|
||||
consoleErrorSpy.restore();
|
||||
processStdoutSpy.restore();
|
||||
processStderrSpy.restore();
|
||||
consoleLogSpy.mockRestore();
|
||||
consoleErrorSpy.mockRestore();
|
||||
processStdoutSpy.mockRestore();
|
||||
processStderrSpy.mockRestore();
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -46,14 +44,12 @@ describe('ForceConsole Option', () => {
|
||||
logger.log('Test log message');
|
||||
|
||||
// Should use console.log when forceConsole is true
|
||||
expect(consoleLogSpy.called).to.be.true;
|
||||
expect(consoleLogSpy).toHaveBeenCalled();
|
||||
// Verify console.log was called with the message
|
||||
const consoleLogCalls = consoleLogSpy
|
||||
.getCalls()
|
||||
.filter(call =>
|
||||
call.args.some(arg => String(arg).includes('Test log message')),
|
||||
);
|
||||
expect(consoleLogCalls.length).to.be.greaterThan(0);
|
||||
const consoleLogCalls = consoleLogSpy.mock.calls.filter(args =>
|
||||
args.some(arg => String(arg).includes('Test log message')),
|
||||
);
|
||||
expect(consoleLogCalls.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should use console.error instead of process.stderr.write', async () => {
|
||||
@@ -61,14 +57,12 @@ describe('ForceConsole Option', () => {
|
||||
logger.error('Test error message');
|
||||
|
||||
// Should use console.error when forceConsole is true
|
||||
expect(consoleErrorSpy.called).to.be.true;
|
||||
expect(consoleErrorSpy).toHaveBeenCalled();
|
||||
// Verify console.error was called with the message
|
||||
const consoleErrorCalls = consoleErrorSpy
|
||||
.getCalls()
|
||||
.filter(call =>
|
||||
call.args.some(arg => String(arg).includes('Test error message')),
|
||||
);
|
||||
expect(consoleErrorCalls.length).to.be.greaterThan(0);
|
||||
const consoleErrorCalls = consoleErrorSpy.mock.calls.filter(args =>
|
||||
args.some(arg => String(arg).includes('Test error message')),
|
||||
);
|
||||
expect(consoleErrorCalls.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('should handle GET request with forceConsole option enabled', () => {
|
||||
@@ -77,17 +71,17 @@ describe('ForceConsole Option', () => {
|
||||
});
|
||||
|
||||
describe('When forceConsole is false (default)', () => {
|
||||
let consoleLogSpy: sinon.SinonSpy;
|
||||
let consoleErrorSpy: sinon.SinonSpy;
|
||||
let processStdoutSpy: sinon.SinonSpy;
|
||||
let processStderrSpy: sinon.SinonSpy;
|
||||
let consoleLogSpy: ReturnType<typeof vi.fn>;
|
||||
let consoleErrorSpy: ReturnType<typeof vi.fn>;
|
||||
let processStdoutSpy: ReturnType<typeof vi.fn>;
|
||||
let processStderrSpy: ReturnType<typeof vi.fn>;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Spy on console and process methods
|
||||
consoleLogSpy = sinon.spy(console, 'log');
|
||||
consoleErrorSpy = sinon.spy(console, 'error');
|
||||
processStdoutSpy = sinon.spy(process.stdout, 'write');
|
||||
processStderrSpy = sinon.spy(process.stderr, 'write');
|
||||
consoleLogSpy = vi.spyOn(console, 'log');
|
||||
consoleErrorSpy = vi.spyOn(console, 'error');
|
||||
processStdoutSpy = vi.spyOn(process.stdout, 'write');
|
||||
processStderrSpy = vi.spyOn(process.stderr, 'write');
|
||||
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
@@ -102,10 +96,10 @@ describe('ForceConsole Option', () => {
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
consoleLogSpy.restore();
|
||||
consoleErrorSpy.restore();
|
||||
processStdoutSpy.restore();
|
||||
processStderrSpy.restore();
|
||||
consoleLogSpy.mockRestore();
|
||||
consoleErrorSpy.mockRestore();
|
||||
processStdoutSpy.mockRestore();
|
||||
processStderrSpy.mockRestore();
|
||||
await app.close();
|
||||
});
|
||||
|
||||
@@ -113,31 +107,31 @@ describe('ForceConsole Option', () => {
|
||||
const logger = new ConsoleLogger('TestContext');
|
||||
|
||||
// Reset spy to ensure clean state
|
||||
consoleLogSpy.resetHistory();
|
||||
consoleLogSpy.mockClear();
|
||||
|
||||
logger.log('Test log message');
|
||||
|
||||
// When forceConsole is false, should not call console.log
|
||||
expect(consoleLogSpy.called).to.be.false;
|
||||
expect(consoleLogSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not directly call console.error when forceConsole is false', async () => {
|
||||
const logger = new ConsoleLogger('TestContext');
|
||||
|
||||
// Reset spy to ensure clean state
|
||||
consoleErrorSpy.resetHistory();
|
||||
consoleErrorSpy.mockClear();
|
||||
|
||||
logger.error('Test error message');
|
||||
|
||||
// When forceConsole is false, should not call console.error
|
||||
expect(consoleErrorSpy.called).to.be.false;
|
||||
expect(consoleErrorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('When forceConsole is set via NestFactory.create', () => {
|
||||
it('should apply forceConsole to the default logger', async () => {
|
||||
const consoleLogSpy = sinon.spy(console, 'log');
|
||||
const processStdoutSpy = sinon.spy(process.stdout, 'write');
|
||||
const consoleLogSpy = vi.spyOn(console, 'log');
|
||||
const processStdoutSpy = vi.spyOn(process.stdout, 'write');
|
||||
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
imports: [AppModule],
|
||||
@@ -153,10 +147,10 @@ describe('ForceConsole Option', () => {
|
||||
const logger = new ConsoleLogger('AppContext', { forceConsole: true });
|
||||
logger.log('Application started');
|
||||
|
||||
expect(consoleLogSpy.called).to.be.true;
|
||||
expect(consoleLogSpy).toHaveBeenCalled();
|
||||
|
||||
consoleLogSpy.restore();
|
||||
processStdoutSpy.restore();
|
||||
consoleLogSpy.mockRestore();
|
||||
processStdoutSpy.mockRestore();
|
||||
await testApp.close();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { APP_GUARD } from '@nestjs/core';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
@Injectable()
|
||||
export class AuthGuard {
|
||||
@@ -33,10 +33,31 @@ function createTestModule(guard) {
|
||||
describe('Guards', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it(`should prevent access (unauthorized)`, async () => {
|
||||
app = (await createTestModule(new AuthGuard())).createNestApplication();
|
||||
|
||||
await app.init();
|
||||
return request(app.getHttpServer()).get('/hello').expect(401);
|
||||
return request(app.getHttpServer())
|
||||
.get('/hello')
|
||||
.expect(401)
|
||||
.expect(({ body }) => {
|
||||
expect(body.message).toBe('Unauthorized');
|
||||
expect(body.statusCode).toBe(401);
|
||||
});
|
||||
});
|
||||
|
||||
it(`should allow access when guard returns true`, async () => {
|
||||
const allowGuard = { canActivate: () => true };
|
||||
app = (await createTestModule(allowGuard)).createNestApplication();
|
||||
|
||||
await app.init();
|
||||
return request(app.getHttpServer())
|
||||
.get('/hello')
|
||||
.expect(200)
|
||||
.expect('Hello world!');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as request from 'supertest';
|
||||
import request from 'supertest';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Hello world (default adapter)', () => {
|
||||
let server;
|
||||
|
||||
@@ -9,8 +9,8 @@ import { APP_INTERCEPTOR } from '@nestjs/core';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { of } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const RETURN_VALUE = 'test';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { INestApplication } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Hello world (default adapter)', () => {
|
||||
let server;
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Response } from 'express';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const INCLUDED_VALUE = 'test_included';
|
||||
const RETURN_VALUE = 'test';
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
Module,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import request from 'supertest';
|
||||
|
||||
const RETURN_VALUE_A = 'test_A';
|
||||
const RETURN_VALUE_B = 'test_B';
|
||||
|
||||
@@ -15,10 +15,9 @@ import {
|
||||
NestFastifyApplication,
|
||||
} from '@nestjs/platform-fastify';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
describe('Middleware (FastifyAdapter)', () => {
|
||||
let app: NestFastifyApplication;
|
||||
@@ -117,7 +116,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/hello',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(RETURN_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(RETURN_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(TestController)`, () => {
|
||||
@@ -126,7 +125,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/test',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(SCOPED_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(SCOPED_VALUE));
|
||||
});
|
||||
|
||||
it(`query?test=${QUERY_VALUE} forRoutes(query)`, () => {
|
||||
@@ -138,7 +137,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
test: QUERY_VALUE,
|
||||
},
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(QUERY_VALUE));
|
||||
});
|
||||
|
||||
it(`${QUERY_VALUE}?test=${QUERY_VALUE} forRoutes(${QUERY_VALUE})`, () => {
|
||||
@@ -150,7 +149,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
test: QUERY_VALUE,
|
||||
},
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(QUERY_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(QUERY_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(tests/*path)`, () => {
|
||||
@@ -159,7 +158,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/tests/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(express_style_wildcard/*)`, () => {
|
||||
@@ -168,7 +167,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/express_style_wildcard/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(legacy_style_wildcard/*)`, () => {
|
||||
@@ -177,7 +176,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/legacy_style_wildcard/wildcard_nested',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`forRoutes(req/url/)`, () => {
|
||||
@@ -187,7 +186,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: `/req/url${reqUrl}`,
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(REQ_URL_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(REQ_URL_VALUE));
|
||||
});
|
||||
|
||||
it(`GET forRoutes(POST tests/included)`, () => {
|
||||
@@ -196,7 +195,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'GET',
|
||||
url: '/tests/included',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(WILDCARD_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(WILDCARD_VALUE));
|
||||
});
|
||||
|
||||
it(`POST forRoutes(POST tests/included)`, () => {
|
||||
@@ -205,7 +204,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'POST',
|
||||
url: '/tests/included',
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(INCLUDED_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(INCLUDED_VALUE));
|
||||
});
|
||||
|
||||
it(`GET forRoutes(POST /tests/%69ncluded) - ensure middleware is executed correctly with encoded characters`, () => {
|
||||
@@ -214,7 +213,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
method: 'POST',
|
||||
url: '/tests/%69ncluded', // 'i' character is encoded
|
||||
})
|
||||
.then(({ payload }) => expect(payload).to.be.eql(INCLUDED_VALUE));
|
||||
.then(({ payload }) => expect(payload).toEqual(INCLUDED_VALUE));
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -329,7 +328,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/a/b/c',
|
||||
})
|
||||
.then(({ payload }) => {
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
@@ -346,7 +345,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/a/b',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
@@ -363,7 +362,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/a',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
@@ -380,7 +379,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/similar',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
@@ -397,7 +396,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/similar/test',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
@@ -414,7 +413,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/similar/arbitrary',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
actual: 1,
|
||||
@@ -494,7 +493,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/api/pong',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
pong: 'pong',
|
||||
@@ -513,7 +512,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/api',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
pong: 'pong',
|
||||
@@ -531,7 +530,7 @@ describe('Middleware (FastifyAdapter)', () => {
|
||||
url: '/pong',
|
||||
})
|
||||
.then(({ payload }) =>
|
||||
expect(payload).to.be.eql(
|
||||
expect(payload).toEqual(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
pong: 'pong',
|
||||
|
||||
@@ -7,10 +7,8 @@ import {
|
||||
NestMiddleware,
|
||||
Module,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '../../../packages/testing';
|
||||
import * as request from 'supertest';
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { Test } from '../../../packages/testing.js';
|
||||
import request from 'supertest';
|
||||
/**
|
||||
* Number of times that the middleware was executed.
|
||||
*/
|
||||
|
||||
@@ -6,14 +6,14 @@ import {
|
||||
Module,
|
||||
RequestMethod,
|
||||
Version,
|
||||
VERSION_NEUTRAL,
|
||||
VersioningOptions,
|
||||
VersioningType,
|
||||
VERSION_NEUTRAL,
|
||||
} from '@nestjs/common';
|
||||
import { CustomVersioningOptions } from '@nestjs/common/interfaces';
|
||||
import { CustomVersioningOptions } from '@nestjs/common/interfaces/index.js';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const RETURN_VALUE = 'test';
|
||||
const VERSIONED_VALUE = 'test_versioned';
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
Module,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const RETURN_VALUE = 'test';
|
||||
const SCOPED_VALUE = 'test_scoped';
|
||||
|
||||
@@ -7,8 +7,8 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { RouterModule } from '@nestjs/core';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import { AppModule } from '../src/app.module';
|
||||
import request from 'supertest';
|
||||
import { AppModule } from '../src/app.module.js';
|
||||
|
||||
const RETURN_VALUE = 'test';
|
||||
const SCOPED_VALUE = 'test_scoped';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Controller, Get, INestApplication, Module } from '@nestjs/common';
|
||||
import { RouterModule, Routes } from '@nestjs/core';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as request from 'supertest';
|
||||
import request from 'supertest';
|
||||
|
||||
describe('RouterModule', () => {
|
||||
let app: INestApplication;
|
||||
@@ -66,7 +66,7 @@ describe('RouterModule', () => {
|
||||
})
|
||||
class AppModule {}
|
||||
|
||||
before(async () => {
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
imports: [MainModule, AppModule],
|
||||
}).compile();
|
||||
|
||||
166
integration/hello-world/e2e/schema-in-pipes.spec.ts
Normal file
166
integration/hello-world/e2e/schema-in-pipes.spec.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import {
|
||||
ArgumentMetadata,
|
||||
Body,
|
||||
Controller,
|
||||
createParamDecorator,
|
||||
ExecutionContext,
|
||||
Get,
|
||||
INestApplication,
|
||||
Injectable,
|
||||
Module,
|
||||
Param,
|
||||
PipeTransform,
|
||||
Post,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
||||
import request from 'supertest';
|
||||
|
||||
const testSchema: StandardSchemaV1 = {
|
||||
'~standard': {
|
||||
version: 1,
|
||||
vendor: 'test',
|
||||
validate: (value: unknown) => ({ value }),
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* A pipe that captures the ArgumentMetadata it receives,
|
||||
* so the test can verify that `schema` is propagated.
|
||||
*/
|
||||
@Injectable()
|
||||
class SchemaCaptorPipe implements PipeTransform {
|
||||
static lastMetadata: ArgumentMetadata | undefined;
|
||||
|
||||
transform(value: any, metadata: ArgumentMetadata) {
|
||||
SchemaCaptorPipe.lastMetadata = metadata;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
const CustomParam = createParamDecorator(
|
||||
(data: unknown, ctx: ExecutionContext) => {
|
||||
return ctx.switchToHttp().getRequest().query;
|
||||
},
|
||||
);
|
||||
|
||||
@Controller('schema-test')
|
||||
class SchemaTestController {
|
||||
@Post('body')
|
||||
bodyWithSchema(
|
||||
@Body({ schema: testSchema, pipes: [SchemaCaptorPipe] }) body: any,
|
||||
) {
|
||||
return { received: body };
|
||||
}
|
||||
|
||||
@Get('query')
|
||||
queryWithSchema(
|
||||
@Query({ schema: testSchema, pipes: [SchemaCaptorPipe] }) query: any,
|
||||
) {
|
||||
return { received: query };
|
||||
}
|
||||
|
||||
@Get('param/:id')
|
||||
paramWithSchema(
|
||||
@Param('id', { schema: testSchema, pipes: [SchemaCaptorPipe] }) id: string,
|
||||
) {
|
||||
return { received: id };
|
||||
}
|
||||
|
||||
@Get('custom')
|
||||
customWithSchema(
|
||||
@CustomParam({ schema: testSchema, pipes: [SchemaCaptorPipe] }) value: any,
|
||||
) {
|
||||
return { received: value };
|
||||
}
|
||||
|
||||
@Post('body-property')
|
||||
bodyPropertyWithSchema(
|
||||
@Body('name', { schema: testSchema, pipes: [SchemaCaptorPipe] })
|
||||
name: string,
|
||||
) {
|
||||
return { received: name };
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
controllers: [SchemaTestController],
|
||||
providers: [SchemaCaptorPipe],
|
||||
})
|
||||
class SchemaTestModule {}
|
||||
|
||||
describe('Schema propagation to pipes', () => {
|
||||
let app: INestApplication;
|
||||
let server: any;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [SchemaTestModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
server = app.getHttpServer();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
SchemaCaptorPipe.lastMetadata = undefined;
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it('should pass schema to pipe via @Body(options)', async () => {
|
||||
await request(server)
|
||||
.post('/schema-test/body')
|
||||
.send({ name: 'test' })
|
||||
.expect(201);
|
||||
|
||||
expect(SchemaCaptorPipe.lastMetadata).toBeDefined();
|
||||
expect(SchemaCaptorPipe.lastMetadata!.schema).toBe(testSchema);
|
||||
expect(SchemaCaptorPipe.lastMetadata!.type).toBe('body');
|
||||
});
|
||||
|
||||
it('should pass schema to pipe via @Query(options)', async () => {
|
||||
await request(server).get('/schema-test/query?user=john').expect(200);
|
||||
|
||||
expect(SchemaCaptorPipe.lastMetadata).toBeDefined();
|
||||
expect(SchemaCaptorPipe.lastMetadata!.schema).toBe(testSchema);
|
||||
expect(SchemaCaptorPipe.lastMetadata!.type).toBe('query');
|
||||
});
|
||||
|
||||
it('should pass schema to pipe via @Param(property, options)', async () => {
|
||||
await request(server)
|
||||
.get('/schema-test/param/42')
|
||||
.expect(200)
|
||||
.expect({ received: '42' });
|
||||
|
||||
expect(SchemaCaptorPipe.lastMetadata).toBeDefined();
|
||||
expect(SchemaCaptorPipe.lastMetadata!.schema).toBe(testSchema);
|
||||
expect(SchemaCaptorPipe.lastMetadata!.type).toBe('param');
|
||||
expect(SchemaCaptorPipe.lastMetadata!.data).toBe('id');
|
||||
});
|
||||
|
||||
it('should pass schema to pipe via createParamDecorator(options)', async () => {
|
||||
await request(server).get('/schema-test/custom?key=val').expect(200);
|
||||
|
||||
expect(SchemaCaptorPipe.lastMetadata).toBeDefined();
|
||||
expect(SchemaCaptorPipe.lastMetadata!.schema).toBe(testSchema);
|
||||
expect(SchemaCaptorPipe.lastMetadata!.type).toBe('custom');
|
||||
});
|
||||
|
||||
it('should pass schema to pipe via @Body(property, options)', async () => {
|
||||
await request(server)
|
||||
.post('/schema-test/body-property')
|
||||
.send({ name: 'Alice' })
|
||||
.expect(201)
|
||||
.expect({ received: 'Alice' });
|
||||
|
||||
expect(SchemaCaptorPipe.lastMetadata).toBeDefined();
|
||||
expect(SchemaCaptorPipe.lastMetadata!.schema).toBe(testSchema);
|
||||
expect(SchemaCaptorPipe.lastMetadata!.type).toBe('body');
|
||||
expect(SchemaCaptorPipe.lastMetadata!.data).toBe('name');
|
||||
});
|
||||
});
|
||||
316
integration/hello-world/e2e/standard-schema-serializer.spec.ts
Normal file
316
integration/hello-world/e2e/standard-schema-serializer.spec.ts
Normal file
@@ -0,0 +1,316 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
INestApplication,
|
||||
Module,
|
||||
SerializeOptions,
|
||||
StandardSchemaSerializerInterceptor,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { APP_INTERCEPTOR, Reflector } from '@nestjs/core';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
||||
import request from 'supertest';
|
||||
|
||||
// ─── Test schemas ──────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Schema that strips out the `password` field (simulating a "safe user" DTO).
|
||||
*/
|
||||
const safeUserSchema: StandardSchemaV1 = {
|
||||
'~standard': {
|
||||
version: 1,
|
||||
vendor: 'test',
|
||||
validate: (value: unknown) => {
|
||||
const { password, ...safe } = value as Record<string, unknown>;
|
||||
return { value: safe };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Schema that adds a `serialized: true` flag (useful for asserting the schema ran).
|
||||
*/
|
||||
const flagSchema: StandardSchemaV1 = {
|
||||
'~standard': {
|
||||
version: 1,
|
||||
vendor: 'test',
|
||||
validate: (value: unknown) => ({
|
||||
value: { ...(value as any), serialized: true },
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Schema that always fails — used for the error case.
|
||||
*/
|
||||
const failingSchema: StandardSchemaV1 = {
|
||||
'~standard': {
|
||||
version: 1,
|
||||
vendor: 'test',
|
||||
validate: () => ({
|
||||
issues: [{ message: 'not allowed' }],
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Async schema — validates that the interceptor awaits promises.
|
||||
*/
|
||||
const asyncSchema: StandardSchemaV1 = {
|
||||
'~standard': {
|
||||
version: 1,
|
||||
vendor: 'test',
|
||||
validate: async (value: unknown) => ({
|
||||
value: { ...(value as any), async: true },
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
// ─── Controllers ───────────────────────────────────────────────
|
||||
|
||||
@Controller('serializer')
|
||||
@UseInterceptors(StandardSchemaSerializerInterceptor)
|
||||
class SerializerTestController {
|
||||
@Get('user')
|
||||
@SerializeOptions({ schema: safeUserSchema })
|
||||
getUser() {
|
||||
return { id: 1, name: 'Alice', password: 'secret123' };
|
||||
}
|
||||
|
||||
@Get('users')
|
||||
@SerializeOptions({ schema: safeUserSchema })
|
||||
getUsers() {
|
||||
return [
|
||||
{ id: 1, name: 'Alice', password: 'pw1' },
|
||||
{ id: 2, name: 'Bob', password: 'pw2' },
|
||||
];
|
||||
}
|
||||
|
||||
@Get('flagged')
|
||||
@SerializeOptions({ schema: flagSchema })
|
||||
getFlagged() {
|
||||
return { id: 1 };
|
||||
}
|
||||
|
||||
@Get('no-schema')
|
||||
getNoSchema() {
|
||||
return { id: 1, secret: 'visible' };
|
||||
}
|
||||
|
||||
@Get('failing')
|
||||
@SerializeOptions({ schema: failingSchema })
|
||||
getFailing() {
|
||||
return { id: 1 };
|
||||
}
|
||||
|
||||
@Get('async')
|
||||
@SerializeOptions({ schema: asyncSchema })
|
||||
getAsync() {
|
||||
return { id: 1 };
|
||||
}
|
||||
|
||||
@Get('primitive')
|
||||
@SerializeOptions({ schema: failingSchema })
|
||||
getPrimitive() {
|
||||
return 'plain string';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller-level schema applied via class decorator — all routes inherit it.
|
||||
*/
|
||||
@Controller('class-level')
|
||||
@UseInterceptors(StandardSchemaSerializerInterceptor)
|
||||
@SerializeOptions({ schema: safeUserSchema })
|
||||
class ClassLevelSerializerController {
|
||||
@Get('user')
|
||||
getUser() {
|
||||
return { id: 1, name: 'Carol', password: 'secret' };
|
||||
}
|
||||
|
||||
@Get('override')
|
||||
@SerializeOptions({ schema: flagSchema })
|
||||
getOverride() {
|
||||
return { id: 1, name: 'Carol', password: 'secret' };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller demonstrating global interceptor registration with a default schema.
|
||||
*/
|
||||
@Controller('global')
|
||||
class GlobalSerializerController {
|
||||
@Get('default')
|
||||
getDefault() {
|
||||
return { id: 1, name: 'Dave', password: 'global-secret' };
|
||||
}
|
||||
|
||||
@Get('override')
|
||||
@SerializeOptions({ schema: flagSchema })
|
||||
getOverride() {
|
||||
return { id: 1 };
|
||||
}
|
||||
}
|
||||
|
||||
@Module({
|
||||
controllers: [SerializerTestController, ClassLevelSerializerController],
|
||||
})
|
||||
class SerializerTestModule {}
|
||||
|
||||
@Module({
|
||||
controllers: [GlobalSerializerController],
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INTERCEPTOR,
|
||||
useFactory: (reflector: Reflector) =>
|
||||
new StandardSchemaSerializerInterceptor(reflector, {
|
||||
schema: safeUserSchema,
|
||||
}),
|
||||
inject: [Reflector],
|
||||
},
|
||||
],
|
||||
})
|
||||
class GlobalSerializerTestModule {}
|
||||
|
||||
// ─── Tests ─────────────────────────────────────────────────────
|
||||
|
||||
describe('StandardSchemaSerializerInterceptor (integration)', () => {
|
||||
let app: INestApplication;
|
||||
|
||||
afterEach(async () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
describe('handler-level @SerializeOptions', () => {
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [SerializerTestModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('should strip fields via schema on a single object', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/user')
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect(body).toEqual({ id: 1, name: 'Alice' });
|
||||
expect(body).not.toHaveProperty('password');
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply schema to each item in an array response', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/users')
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect(body).toEqual([
|
||||
{ id: 1, name: 'Alice' },
|
||||
{ id: 2, name: 'Bob' },
|
||||
]);
|
||||
body.forEach((item: any) =>
|
||||
expect(item).not.toHaveProperty('password'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should augment response through the schema', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/flagged')
|
||||
.expect(200)
|
||||
.expect({ id: 1, serialized: true });
|
||||
});
|
||||
|
||||
it('should return response unchanged when no schema is set', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/no-schema')
|
||||
.expect(200)
|
||||
.expect({ id: 1, secret: 'visible' });
|
||||
});
|
||||
|
||||
it('should return 500 when schema validation fails', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/failing')
|
||||
.expect(500);
|
||||
});
|
||||
|
||||
it('should handle async schemas', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/async')
|
||||
.expect(200)
|
||||
.expect({ id: 1, async: true });
|
||||
});
|
||||
|
||||
it('should pass primitive values through even when a schema is set', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/serializer/primitive')
|
||||
.expect(200)
|
||||
.expect(({ text }) => {
|
||||
expect(text).toBe('plain string');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('class-level @SerializeOptions', () => {
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [SerializerTestModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('should apply class-level schema to all routes', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/class-level/user')
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect(body).toEqual({ id: 1, name: 'Carol' });
|
||||
expect(body).not.toHaveProperty('password');
|
||||
});
|
||||
});
|
||||
|
||||
it('should allow handler-level schema to override class-level', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/class-level/override')
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
// flagSchema adds `serialized: true` but does NOT strip password
|
||||
expect(body).toHaveProperty('serialized', true);
|
||||
expect(body).toHaveProperty('password', 'secret');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('global interceptor with default schema', () => {
|
||||
beforeEach(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
imports: [GlobalSerializerTestModule],
|
||||
}).compile();
|
||||
|
||||
app = module.createNestApplication();
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it('should apply the default schema globally', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/global/default')
|
||||
.expect(200)
|
||||
.expect(({ body }) => {
|
||||
expect(body).toEqual({ id: 1, name: 'Dave' });
|
||||
expect(body).not.toHaveProperty('password');
|
||||
});
|
||||
});
|
||||
|
||||
it('should let @SerializeOptions override the global default', () => {
|
||||
return request(app.getHttpServer())
|
||||
.get('/global/override')
|
||||
.expect(200)
|
||||
.expect({ id: 1, serialized: true });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HelloModule } from './hello/hello.module';
|
||||
import { HostArrayModule } from './host-array/host-array.module';
|
||||
import { HostModule } from './host/host.module';
|
||||
import { HelloModule } from './hello/hello.module.js';
|
||||
import { HostArrayModule } from './host-array/host-array.module.js';
|
||||
import { HostModule } from './host/host.module.js';
|
||||
|
||||
@Module({
|
||||
imports: [HelloModule, HostModule, HostArrayModule],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Controller, Get, Header, Param } from '@nestjs/common';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { HelloService } from './hello.service';
|
||||
import { UserByIdPipe } from './users/user-by-id.pipe';
|
||||
import { HelloService } from './hello.service.js';
|
||||
import { UserByIdPipe } from './users/user-by-id.pipe.js';
|
||||
|
||||
@Controller('hello')
|
||||
export class HelloController {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HelloController } from './hello.controller';
|
||||
import { HelloService } from './hello.service';
|
||||
import { UsersService } from './users/users.service';
|
||||
import { HelloController } from './hello.controller.js';
|
||||
import { HelloService } from './hello.service.js';
|
||||
import { UsersService } from './users/users.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [HelloController],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersService } from './users.service.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserByIdPipe implements PipeTransform<string> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Controller, Get, Header, HostParam, Param } from '@nestjs/common';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { HostArrayService } from './host-array.service';
|
||||
import { UserByIdPipe } from './users/user-by-id.pipe';
|
||||
import { HostArrayService } from './host-array.service.js';
|
||||
import { UserByIdPipe } from './users/user-by-id.pipe.js';
|
||||
|
||||
@Controller({
|
||||
path: 'host-array',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HostArrayController } from './host-array.controller';
|
||||
import { HostArrayService } from './host-array.service';
|
||||
import { UsersService } from './users/users.service';
|
||||
import { HostArrayController } from './host-array.controller.js';
|
||||
import { HostArrayService } from './host-array.service.js';
|
||||
import { UsersService } from './users/users.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [HostArrayController],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersService } from './users.service.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserByIdPipe implements PipeTransform<string> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Controller, Get, Header, HostParam, Param } from '@nestjs/common';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { HostService } from './host.service';
|
||||
import { UserByIdPipe } from './users/user-by-id.pipe';
|
||||
import { HostService } from './host.service.js';
|
||||
import { UserByIdPipe } from './users/user-by-id.pipe.js';
|
||||
|
||||
@Controller({
|
||||
path: 'host',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { HostController } from './host.controller';
|
||||
import { HostService } from './host.service';
|
||||
import { UsersService } from './users/users.service';
|
||||
import { HostController } from './host.controller.js';
|
||||
import { HostService } from './host.service.js';
|
||||
import { UsersService } from './users/users.service.js';
|
||||
|
||||
@Module({
|
||||
controllers: [HostController],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersService } from './users.service.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserByIdPipe implements PipeTransform<string> {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["vitest/globals"],
|
||||
"module": "commonjs",
|
||||
"declaration": false,
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"esModuleInterop": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "ES2021",
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"strictNullChecks": true,
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { BeforeApplicationShutdown, Injectable, Module } from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { expect } from 'chai';
|
||||
import * as Sinon from 'sinon';
|
||||
|
||||
@Injectable()
|
||||
class TestInjectable implements BeforeApplicationShutdown {
|
||||
beforeApplicationShutdown = Sinon.spy();
|
||||
beforeApplicationShutdown = vi.fn();
|
||||
}
|
||||
|
||||
describe('BeforeApplicationShutdown', () => {
|
||||
@@ -17,13 +14,13 @@ describe('BeforeApplicationShutdown', () => {
|
||||
const app = module.createNestApplication();
|
||||
await app.close();
|
||||
const instance = module.get(TestInjectable);
|
||||
expect(instance.beforeApplicationShutdown.called).to.be.true;
|
||||
expect(instance.beforeApplicationShutdown).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should sort modules by distance (topological sort) - DESC order', async () => {
|
||||
@Injectable()
|
||||
class BB implements BeforeApplicationShutdown {
|
||||
beforeApplicationShutdown = Sinon.spy();
|
||||
beforeApplicationShutdown = vi.fn();
|
||||
}
|
||||
|
||||
@Module({
|
||||
@@ -35,7 +32,7 @@ describe('BeforeApplicationShutdown', () => {
|
||||
@Injectable()
|
||||
class AA implements BeforeApplicationShutdown {
|
||||
constructor(private bb: BB) {}
|
||||
beforeApplicationShutdown = Sinon.spy();
|
||||
beforeApplicationShutdown = vi.fn();
|
||||
}
|
||||
@Module({
|
||||
imports: [B],
|
||||
@@ -53,9 +50,8 @@ describe('BeforeApplicationShutdown', () => {
|
||||
|
||||
const aa = module.get(AA);
|
||||
const bb = module.get(BB);
|
||||
Sinon.assert.callOrder(
|
||||
aa.beforeApplicationShutdown,
|
||||
bb.beforeApplicationShutdown,
|
||||
);
|
||||
expect(
|
||||
aa.beforeApplicationShutdown.mock.invocationCallOrder[0],
|
||||
).toBeLessThan(bb.beforeApplicationShutdown.mock.invocationCallOrder[0]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,71 +1,81 @@
|
||||
import { expect } from 'chai';
|
||||
import { spawnSync } from 'child_process';
|
||||
import { join } from 'path';
|
||||
|
||||
const nodeCmd = process.execPath;
|
||||
|
||||
function spawnTsNode(...args: string[]) {
|
||||
return spawnSync(nodeCmd, ['--import', 'jiti/register', ...args]);
|
||||
}
|
||||
|
||||
describe('enableShutdownHooks', () => {
|
||||
it('should call the correct hooks if any shutdown signal gets invoked', done => {
|
||||
const result = spawnSync('ts-node', [
|
||||
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGHUP',
|
||||
]);
|
||||
const calls = result.stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((call: string) => call.trim());
|
||||
expect(calls[0]).to.equal('beforeApplicationShutdown SIGHUP');
|
||||
expect(calls[1]).to.equal('onApplicationShutdown SIGHUP');
|
||||
done();
|
||||
}).timeout(10000);
|
||||
it('should call the correct hooks if any shutdown signal gets invoked', () =>
|
||||
new Promise<void>(done => {
|
||||
const result = spawnTsNode(
|
||||
join(import.meta.dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGHUP',
|
||||
);
|
||||
const calls = result.stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((call: string) => call.trim());
|
||||
expect(calls[0]).toBe('beforeApplicationShutdown SIGHUP');
|
||||
expect(calls[1]).toBe('onApplicationShutdown SIGHUP');
|
||||
done();
|
||||
}));
|
||||
|
||||
it('should call the correct hooks if a specific shutdown signal gets invoked', done => {
|
||||
const result = spawnSync('ts-node', [
|
||||
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGINT',
|
||||
'SIGINT',
|
||||
]);
|
||||
const calls = result.stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((call: string) => call.trim());
|
||||
expect(calls[0]).to.equal('beforeApplicationShutdown SIGINT');
|
||||
expect(calls[1]).to.equal('onApplicationShutdown SIGINT');
|
||||
done();
|
||||
}).timeout(10000);
|
||||
it('should call the correct hooks if a specific shutdown signal gets invoked', () =>
|
||||
new Promise<void>(done => {
|
||||
const result = spawnTsNode(
|
||||
join(import.meta.dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGINT',
|
||||
'SIGINT',
|
||||
);
|
||||
const calls = result.stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((call: string) => call.trim());
|
||||
expect(calls[0]).toBe('beforeApplicationShutdown SIGINT');
|
||||
expect(calls[1]).toBe('onApplicationShutdown SIGINT');
|
||||
done();
|
||||
}));
|
||||
|
||||
it('should ignore system signals which are not specified', done => {
|
||||
const result = spawnSync('ts-node', [
|
||||
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGINT',
|
||||
'SIGHUP',
|
||||
]);
|
||||
expect(result.stdout.toString().trim()).to.be.eq('');
|
||||
done();
|
||||
}).timeout(10000);
|
||||
it('should ignore system signals which are not specified', () =>
|
||||
new Promise<void>(done => {
|
||||
const result = spawnTsNode(
|
||||
join(import.meta.dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGINT',
|
||||
'SIGHUP',
|
||||
);
|
||||
expect(result.stdout.toString().trim()).toBe('');
|
||||
done();
|
||||
}));
|
||||
|
||||
it('should ignore system signals if "enableShutdownHooks" was not called', done => {
|
||||
const result = spawnSync('ts-node', [
|
||||
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGINT',
|
||||
'NONE',
|
||||
]);
|
||||
expect(result.stdout.toString().trim()).to.be.eq('');
|
||||
done();
|
||||
}).timeout(10000);
|
||||
it('should ignore system signals if "enableShutdownHooks" was not called', () =>
|
||||
new Promise<void>(done => {
|
||||
const result = spawnTsNode(
|
||||
join(import.meta.dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGINT',
|
||||
'NONE',
|
||||
);
|
||||
expect(result.stdout.toString().trim()).toBe('');
|
||||
done();
|
||||
}));
|
||||
|
||||
it('should call the correct hooks with useProcessExit option', done => {
|
||||
const result = spawnSync('ts-node', [
|
||||
join(__dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGHUP',
|
||||
'SIGHUP',
|
||||
'graceful',
|
||||
]);
|
||||
const calls = result.stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((call: string) => call.trim());
|
||||
expect(calls[0]).to.equal('beforeApplicationShutdown SIGHUP');
|
||||
expect(calls[1]).to.equal('onApplicationShutdown SIGHUP');
|
||||
expect(result.status).to.equal(0);
|
||||
done();
|
||||
}).timeout(10000);
|
||||
it('should call the correct hooks with useProcessExit option', () =>
|
||||
new Promise<void>(done => {
|
||||
const result = spawnTsNode(
|
||||
join(import.meta.dirname, '../src/enable-shutdown-hooks-main.ts'),
|
||||
'SIGHUP',
|
||||
'SIGHUP',
|
||||
'graceful',
|
||||
);
|
||||
const calls = result.stdout
|
||||
.toString()
|
||||
.split('\n')
|
||||
.map((call: string) => call.trim());
|
||||
expect(calls[0]).toBe('beforeApplicationShutdown SIGHUP');
|
||||
expect(calls[1]).toBe('onApplicationShutdown SIGHUP');
|
||||
expect(result.status).toBe(0);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Test } from '@nestjs/testing';
|
||||
import * as Sinon from 'sinon';
|
||||
import {
|
||||
BeforeApplicationShutdown,
|
||||
Injectable,
|
||||
OnApplicationBootstrap,
|
||||
OnApplicationShutdown,
|
||||
OnModuleDestroy,
|
||||
OnModuleInit,
|
||||
BeforeApplicationShutdown,
|
||||
} from '@nestjs/common';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
@Injectable()
|
||||
class TestInjectable
|
||||
@@ -18,11 +17,11 @@ class TestInjectable
|
||||
OnApplicationShutdown,
|
||||
BeforeApplicationShutdown
|
||||
{
|
||||
onApplicationBootstrap = Sinon.spy();
|
||||
beforeApplicationShutdown = Sinon.spy();
|
||||
onApplicationShutdown = Sinon.spy();
|
||||
onModuleDestroy = Sinon.spy();
|
||||
onModuleInit = Sinon.spy();
|
||||
onApplicationBootstrap = vi.fn();
|
||||
beforeApplicationShutdown = vi.fn();
|
||||
onApplicationShutdown = vi.fn();
|
||||
onModuleDestroy = vi.fn();
|
||||
onModuleInit = vi.fn();
|
||||
}
|
||||
|
||||
describe('Lifecycle Hook Order', () => {
|
||||
@@ -36,12 +35,17 @@ describe('Lifecycle Hook Order', () => {
|
||||
await app.close();
|
||||
|
||||
const instance = module.get(TestInjectable);
|
||||
Sinon.assert.callOrder(
|
||||
const order = [
|
||||
instance.onModuleInit,
|
||||
instance.onApplicationBootstrap,
|
||||
instance.onModuleDestroy,
|
||||
instance.beforeApplicationShutdown,
|
||||
instance.onApplicationShutdown,
|
||||
);
|
||||
];
|
||||
for (let i = 0; i < order.length - 1; i++) {
|
||||
expect(order[i].mock.invocationCallOrder[0]).toBeLessThan(
|
||||
order[i + 1].mock.invocationCallOrder[0],
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user