@appsemble/node-utils 0.30.14-test.6 → 0.32.1-test.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +3 -3
  2. package/app.js +8 -0
  3. package/assets.d.ts +16 -0
  4. package/assets.js +65 -0
  5. package/authentication.d.ts +1 -1
  6. package/container/helpers.d.ts +1 -1
  7. package/container/helpers.js +1 -0
  8. package/container/logs.js +8 -5
  9. package/container/operations.js +22 -14
  10. package/container/scale.js +3 -2
  11. package/container/specs.js +1 -1
  12. package/fs.js +4 -0
  13. package/getAppsembleMessages.js +2 -0
  14. package/getMessagesUtil.js +5 -4
  15. package/getValidTrainings.d.ts +8 -0
  16. package/getValidTrainings.js +47 -0
  17. package/icon.js +5 -0
  18. package/index.d.ts +5 -1
  19. package/index.js +5 -1
  20. package/interceptors.js +1 -1
  21. package/koa.d.ts +13 -1
  22. package/koa.js +17 -1
  23. package/logger.js +5 -3
  24. package/middleware/loggerMiddleware.js +1 -0
  25. package/odata.js +2 -1
  26. package/package.json +22 -14
  27. package/parsers.d.ts +1 -0
  28. package/parsers.js +130 -0
  29. package/render.js +1 -1
  30. package/resource.d.ts +18 -3
  31. package/resource.js +50 -10
  32. package/s3.d.ts +18 -0
  33. package/s3.js +131 -0
  34. package/server/controllers/common/apps/assets/createGetAppAssetByIdController.js +4 -3
  35. package/server/controllers/common/apps/groups/createGetAppGroupsController.js +2 -2
  36. package/server/controllers/common/apps/messages/createGetAppMessagesController.js +2 -0
  37. package/server/controllers/common/apps/resources/createCreateAppResourceController.js +16 -2
  38. package/server/controllers/common/apps/resources/createDeleteAppResourceController.js +2 -2
  39. package/server/controllers/common/apps/resources/createGetAppResourceByIdController.js +3 -3
  40. package/server/controllers/common/apps/resources/createQueryAppResourcesController.js +1 -1
  41. package/server/controllers/common/apps/resources/createUpdateAppResourceController.js +6 -3
  42. package/server/controllers/common/apps/variables/createGetAppVariablesController.js +2 -2
  43. package/server/controllers/main/apps/assets/createCreateAppAssetController.js +4 -4
  44. package/server/controllers/main/apps/resources/createDeleteAppSeedResourcesController.js +2 -2
  45. package/server/routes/appRouter/blockAssetHandler.js +5 -3
  46. package/server/routes/appRouter/blockCssHandler.js +5 -3
  47. package/server/routes/appRouter/bulmaHandler.js +1 -0
  48. package/server/routes/appRouter/cssHandler.js +2 -2
  49. package/server/routes/appRouter/iconHandler.js +4 -1
  50. package/server/routes/appRouter/indexHandler.js +3 -1
  51. package/server/routes/appRouter/manifestHandler.js +2 -2
  52. package/server/routes/appRouter/readmeHandler.js +4 -3
  53. package/server/routes/appRouter/robotsHandler.js +2 -2
  54. package/server/routes/appRouter/screenshotHandler.js +4 -3
  55. package/server/routes/appRouter/serviceWorkerHandler.js +2 -2
  56. package/server/types.d.ts +22 -7
  57. package/server/types.js +7 -1
  58. package/server/utils/actions.js +16 -10
  59. package/server/utils/resources.js +4 -1
  60. package/tinyRouter.js +3 -3
  61. package/uploads.d.ts +2 -0
  62. package/uploads.js +27 -0
  63. package/versions.d.ts +3 -0
  64. package/versions.js +7 -0
  65. package/AppsembleError.test.d.ts +0 -1
  66. package/AppsembleError.test.js +0 -7
  67. package/basicAuth.test.d.ts +0 -1
  68. package/basicAuth.test.js +0 -7
  69. package/formData.test.d.ts +0 -1
  70. package/formData.test.js +0 -93
  71. package/fs.test.d.ts +0 -1
  72. package/fs.test.js +0 -75
  73. package/handleError.test.d.ts +0 -1
  74. package/handleError.test.js +0 -33
  75. package/interceptors.test.d.ts +0 -1
  76. package/interceptors.test.js +0 -83
  77. package/logger.test.d.ts +0 -1
  78. package/logger.test.js +0 -37
  79. package/middleware/error.test.d.ts +0 -1
  80. package/middleware/error.test.js +0 -59
  81. package/middleware/loggerMiddleware.test.d.ts +0 -1
  82. package/middleware/loggerMiddleware.test.js +0 -120
  83. package/readFileOrString.test.d.ts +0 -1
  84. package/readFileOrString.test.js +0 -12
  85. package/server/controllers/common/apps/resources/resources.test.d.ts +0 -1
  86. package/server/controllers/common/apps/resources/resources.test.js +0 -580
  87. package/tinyRouter.test.d.ts +0 -1
  88. package/tinyRouter.test.js +0 -83
  89. package/versions.cjs +0 -4
package/versions.js ADDED
@@ -0,0 +1,7 @@
1
+ import faPkg from '@fortawesome/fontawesome-free/package.json' with { type: 'json' };
2
+ import bulmaPkg from 'bulma/package.json' with { type: 'json' };
3
+ import pkg from './package.json' with { type: 'json' };
4
+ export const { version } = pkg;
5
+ export const faVersion = faPkg.version;
6
+ export const bulmaVersion = bulmaPkg.version;
7
+ //# sourceMappingURL=versions.js.map
@@ -1 +0,0 @@
1
- export {};
@@ -1,7 +0,0 @@
1
- import { expect, it } from 'vitest';
2
- import { AppsembleError } from './AppsembleError.js';
3
- it('should define AppsembleError as its name', () => {
4
- const error = new AppsembleError('message');
5
- expect(error.name).toBe('AppsembleError');
6
- });
7
- //# sourceMappingURL=AppsembleError.test.js.map
@@ -1 +0,0 @@
1
- export {};
package/basicAuth.test.js DELETED
@@ -1,7 +0,0 @@
1
- import { expect, it } from 'vitest';
2
- import { basicAuth } from './basicAuth.js';
3
- it('should serialize credentials', () => {
4
- const result = basicAuth('me', 'password1');
5
- expect(result).toBe('Basic bWU6cGFzc3dvcmQx');
6
- });
7
- //# sourceMappingURL=basicAuth.test.js.map
@@ -1 +0,0 @@
1
- export {};
package/formData.test.js DELETED
@@ -1,93 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createFormData } from './formData.js';
3
- describe('createFormData', () => {
4
- it('should handle strings', () => {
5
- const form = createFormData({ foo: 'bar' });
6
- const boundary = form.getBoundary();
7
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
8
- Content-Disposition: form-data; name="foo"\r
9
- \r
10
- bar\r
11
- --${boundary}--\r
12
- `);
13
- });
14
- it('should handle numbers', () => {
15
- const form = createFormData({ answer: 42 });
16
- const boundary = form.getBoundary();
17
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
18
- Content-Disposition: form-data; name="answer"\r
19
- \r
20
- 42\r
21
- --${boundary}--\r
22
- `);
23
- });
24
- it('should handle booleans', () => {
25
- const form = createFormData({ really: true });
26
- const boundary = form.getBoundary();
27
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
28
- Content-Disposition: form-data; name="really"\r
29
- \r
30
- true\r
31
- --${boundary}--\r
32
- `);
33
- });
34
- it('should handle buffers', () => {
35
- const form = createFormData({ buf: Buffer.from('fer') });
36
- const boundary = form.getBoundary();
37
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
38
- Content-Disposition: form-data; name="buf"\r
39
- Content-Type: application/octet-stream\r
40
- \r
41
- fer\r
42
- --${boundary}--\r
43
- `);
44
- });
45
- it('should handle null', () => {
46
- const form = createFormData({ really: true });
47
- const boundary = form.getBoundary();
48
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
49
- Content-Disposition: form-data; name="really"\r
50
- \r
51
- true\r
52
- --${boundary}--\r
53
- `);
54
- });
55
- it('should ignore undefined', () => {
56
- const form = createFormData({ defined: undefined });
57
- const boundary = form.getBoundary();
58
- expect(String(form.getBuffer())).toBe(`--${boundary}--\r\n`);
59
- });
60
- it('should convert objects to JSON', () => {
61
- const form = createFormData({ deeply: { nested: 'data' } });
62
- const boundary = form.getBoundary();
63
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
64
- Content-Disposition: form-data; name="deeply"\r
65
- \r
66
- {"nested":"data"}\r
67
- --${boundary}--\r
68
- `);
69
- });
70
- it('should append multiple entries if the input is an array', () => {
71
- const form = createFormData({ array: [42, 'bananas', null, { fruit: true }] });
72
- const boundary = form.getBoundary();
73
- expect(String(form.getBuffer())).toBe(`--${boundary}\r
74
- Content-Disposition: form-data; name="array"\r
75
- \r
76
- 42\r
77
- --${boundary}\r
78
- Content-Disposition: form-data; name="array"\r
79
- \r
80
- bananas\r
81
- --${boundary}\r
82
- Content-Disposition: form-data; name="array"\r
83
- \r
84
- null\r
85
- --${boundary}\r
86
- Content-Disposition: form-data; name="array"\r
87
- \r
88
- {"fruit":true}\r
89
- --${boundary}--\r
90
- `);
91
- });
92
- });
93
- //# sourceMappingURL=formData.test.js.map
package/fs.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/fs.test.js DELETED
@@ -1,75 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import { AppsembleError, isErrno, opendirSafe, readData, resolveFixture } from './index.js';
3
- describe('isErrno', () => {
4
- it('should return false for null', () => {
5
- expect(isErrno(null)).toBe(false);
6
- });
7
- it('should return false for miscellaneous objects', () => {
8
- expect(isErrno({})).toBe(false);
9
- });
10
- it('should return true if the object has a string property named code', () => {
11
- expect(isErrno({ code: 'foo' })).toBe(true);
12
- });
13
- it('should return false if the object has a non-string property named code', () => {
14
- expect(isErrno({ code: 42 })).toBe(false);
15
- });
16
- it('should allow to narrow down a specific code', () => {
17
- expect(isErrno({ code: 'ENOENT' }, 'ENOENT')).toBe(true);
18
- expect(isErrno({ code: 'invalid' }, 'ENOENT')).toBe(false);
19
- });
20
- });
21
- describe('readData', () => {
22
- it('should read and parse a JSON file', async () => {
23
- const content = await readData(resolveFixture('json.json'));
24
- expect(content).toStrictEqual([{ json: 'json' }, '{ "json": "json" }\n']);
25
- });
26
- it('should read and parse a YAML file', async () => {
27
- const content = await readData(resolveFixture('yaml.yaml'));
28
- expect(content).toStrictEqual([{ yaml: 'yaml' }, 'yaml: yaml\n']);
29
- });
30
- it('should throw an Appsemble error if file extension is unknown', async () => {
31
- const path = resolveFixture('hello.txt');
32
- await expect(readData(path)).rejects.toThrow(new AppsembleError(`Unknown file extension: ${path}`));
33
- });
34
- it('should throw an Appsemble error if the file can’t be read', async () => {
35
- await expect(readData('non-existent.yaml')).rejects.toThrow(new AppsembleError('Error reading file non-existent.yaml'));
36
- });
37
- it('should throw an Appsemble error if the file can’t be parsed', async () => {
38
- const path = resolveFixture('invalid-json.json');
39
- await expect(readData(path)).rejects.toThrow(AppsembleError);
40
- });
41
- });
42
- describe('opendirSafe', () => {
43
- it('should read a directory', async () => {
44
- const onFile = vi.fn();
45
- await opendirSafe(resolveFixture('test'), onFile);
46
- expect(onFile).toHaveBeenCalledTimes(3);
47
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/bar.txt'), expect.objectContaining({ name: 'bar.txt' }));
48
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/foo.txt'), expect.objectContaining({ name: 'foo.txt' }));
49
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/z'), expect.objectContaining({ name: 'z' }));
50
- });
51
- it('should read a directory recursively if specified', async () => {
52
- const onFile = vi.fn();
53
- await opendirSafe(resolveFixture('test'), onFile, { recursive: true });
54
- expect(onFile).toHaveBeenCalledTimes(5);
55
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/bar.txt'), expect.objectContaining({ name: 'bar.txt' }));
56
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/foo.txt'), expect.objectContaining({ name: 'foo.txt' }));
57
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/z'), expect.objectContaining({ name: 'z' }));
58
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/z/baz.txt'), expect.objectContaining({ name: 'baz.txt' }));
59
- expect(onFile).toHaveBeenCalledWith(resolveFixture('test/z/fooz.txt'), expect.objectContaining({ name: 'fooz.txt' }));
60
- });
61
- it('should throw if the path is not a directory', async () => {
62
- const path = resolveFixture('hello.txt');
63
- await expect(opendirSafe(path, vi.fn())).rejects.toThrow(new AppsembleError(`Expected ${path} to be a directory`));
64
- });
65
- it('should throw if the path doesn’t exist', async () => {
66
- const path = resolveFixture('non-existent');
67
- await expect(opendirSafe(path, vi.fn())).rejects.toThrow(new AppsembleError(`Expected ${path} to be a directory`));
68
- });
69
- it('should not throw if the path doesn’t exist and allowMissing is true', async () => {
70
- const path = resolveFixture('non-existent');
71
- const result = await opendirSafe(path, vi.fn(), { allowMissing: true });
72
- expect(result).toBeUndefined();
73
- });
74
- });
75
- //# sourceMappingURL=fs.test.js.map
@@ -1 +0,0 @@
1
- export {};
@@ -1,33 +0,0 @@
1
- import { beforeEach, expect, it, vi } from 'vitest';
2
- import { AppsembleError } from './AppsembleError.js';
3
- import { handleError } from './handleError.js';
4
- import { logger } from './logger.js';
5
- let yargs;
6
- beforeEach(() => {
7
- yargs = { showHelp: vi.fn() };
8
- vi.spyOn(console, 'error').mockImplementation(null);
9
- vi.spyOn(process, 'exit').mockImplementation(() => null);
10
- vi.spyOn(logger, 'error').mockImplementation(null);
11
- });
12
- it('should show the help message if it is passed a yargs message', () => {
13
- handleError('Command foo not found', undefined, yargs);
14
- // eslint-disable-next-line no-console
15
- expect(console.error).toHaveBeenCalledWith('Command foo not found');
16
- expect(yargs.showHelp).toHaveBeenCalledWith();
17
- expect(logger.error).not.toHaveBeenCalled();
18
- expect(process.exit).toHaveBeenCalledWith(1);
19
- });
20
- it('should log the message of an Appsemble error', () => {
21
- handleError(undefined, new AppsembleError('Oh noez!'), yargs);
22
- expect(yargs.showHelp).not.toHaveBeenCalled();
23
- expect(logger.error).toHaveBeenCalledWith('Oh noez!');
24
- expect(process.exit).toHaveBeenCalledWith(1);
25
- });
26
- it('should log unknown errors raw', () => {
27
- const error = new Error('Oh noez!');
28
- handleError(undefined, error, yargs);
29
- expect(yargs.showHelp).not.toHaveBeenCalled();
30
- expect(logger.error).toHaveBeenCalledWith(error);
31
- expect(process.exit).toHaveBeenCalledWith(1);
32
- });
33
- //# sourceMappingURL=handleError.test.js.map
@@ -1 +0,0 @@
1
- export {};
@@ -1,83 +0,0 @@
1
- import axios from 'axios';
2
- import MockAdapter from 'axios-mock-adapter';
3
- import { highlight } from 'cli-highlight';
4
- import FormData from 'form-data';
5
- import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
6
- import { configureAxios, formData, logger, requestLogger, responseLogger } from './index.js';
7
- function h(content) {
8
- return highlight(content, { language: 'http' });
9
- }
10
- let instance;
11
- let mock;
12
- beforeEach(() => {
13
- vi.useFakeTimers({ now: 0 });
14
- });
15
- describe('formData', () => {
16
- beforeAll(() => {
17
- instance = axios.create();
18
- instance.interceptors.request.use(formData);
19
- mock = new MockAdapter(instance);
20
- });
21
- it('should add headers for form-data requests', async () => {
22
- let headers;
23
- mock.onAny('/').reply((config) => {
24
- ({ headers } = config);
25
- return [200];
26
- });
27
- const form = new FormData();
28
- await instance.post('/', form);
29
- expect(headers).toHaveProperty('Content-Type', expect.stringMatching(/^multipart\/form-data; boundary=/));
30
- });
31
- it('should not add headers to non form-data requests', async () => {
32
- let headers;
33
- mock.onAny('/').reply((config) => {
34
- ({ headers } = config);
35
- return [200];
36
- });
37
- await instance.post('/', {});
38
- expect(headers).toBeUndefined();
39
- });
40
- });
41
- describe('requestLogger', () => {
42
- beforeAll(() => {
43
- instance = axios.create();
44
- instance.interceptors.request.use(requestLogger);
45
- mock = new MockAdapter(instance);
46
- mock.onAny().reply(200);
47
- });
48
- it('should log requests', async () => {
49
- vi.spyOn(logger, 'verbose');
50
- await instance.get('/');
51
- expect(logger.verbose).toHaveBeenCalledWith(`> 0 ${h('GET / HTTP/1.1')}`);
52
- });
53
- });
54
- describe('responseLogger', () => {
55
- beforeAll(() => {
56
- instance = axios.create();
57
- instance.interceptors.response.use(responseLogger);
58
- mock = new MockAdapter(instance);
59
- mock.onAny().reply(200);
60
- });
61
- it('should log responses', async () => {
62
- vi.spyOn(logger, 'verbose');
63
- await instance.get('/');
64
- expect(logger.verbose).toHaveBeenCalledWith(expect.any(String));
65
- });
66
- });
67
- describe('configureAxios', () => {
68
- beforeEach(() => {
69
- vi.spyOn(axios.interceptors.request, 'use').mockImplementation(null);
70
- vi.spyOn(axios.interceptors.response, 'use').mockImplementation(null);
71
- });
72
- it('should set the correct user agent', () => {
73
- configureAxios('TestClient', '1.2.3');
74
- expect(axios.defaults.headers.common['user-agent']).toBe(`TestClient/1.2.3 (Linux x64; Node ${process.version})`);
75
- });
76
- it('should apply all interceptors', () => {
77
- configureAxios('TestClient', '1.2.3');
78
- expect(axios.interceptors.request.use).toHaveBeenCalledWith(formData);
79
- expect(axios.interceptors.request.use).toHaveBeenCalledWith(requestLogger);
80
- expect(axios.interceptors.response.use).toHaveBeenCalledWith(responseLogger);
81
- });
82
- });
83
- //# sourceMappingURL=interceptors.test.js.map
package/logger.test.d.ts DELETED
@@ -1 +0,0 @@
1
- export {};
package/logger.test.js DELETED
@@ -1,37 +0,0 @@
1
- import { afterEach, describe, expect, it } from 'vitest';
2
- import { configureLogger, logger, setLogLevel } from './logger.js';
3
- describe('setLogLevel', () => {
4
- afterEach(() => {
5
- setLogLevel();
6
- });
7
- it('should set the level of the exported logger based on a string', () => {
8
- setLogLevel('verbose');
9
- expect(logger.level).toBe('verbose');
10
- });
11
- it('should set the level of the exported logger based on a number', () => {
12
- setLogLevel(1);
13
- expect(logger.level).toBe('error');
14
- });
15
- it('should set the level of the exported logger based on a numeric string', () => {
16
- setLogLevel('2');
17
- expect(logger.level).toBe('warn');
18
- });
19
- });
20
- describe('configureLogger', () => {
21
- afterEach(() => {
22
- setLogLevel();
23
- });
24
- it('should configure a log level based on the quiet count of the argv', () => {
25
- configureLogger({ quiet: 1 });
26
- expect(logger.level).toBe('warn');
27
- });
28
- it('should configure a log level based on the verbose count of the argv', () => {
29
- configureLogger({ verbose: 1 });
30
- expect(logger.level).toBe('verbose');
31
- });
32
- it('should configure a log level based on the combined quiet and verbose count', () => {
33
- configureLogger({ quiet: 1, verbose: 1 });
34
- expect(logger.level).toBe('info');
35
- });
36
- });
37
- //# sourceMappingURL=logger.test.js.map
@@ -1 +0,0 @@
1
- export {};
@@ -1,59 +0,0 @@
1
- import { request, setTestApp } from 'axios-test-instance';
2
- import Koa from 'koa';
3
- import { beforeEach, describe, expect, it } from 'vitest';
4
- import { errorMiddleware } from './error.js';
5
- import { throwKoaError } from '../koa.js';
6
- describe('errorMiddleware', () => {
7
- let app;
8
- beforeEach(async () => {
9
- app = new Koa();
10
- app.use(errorMiddleware());
11
- await setTestApp(app);
12
- });
13
- it('should catch Koa errors', async () => {
14
- app.use((ctx) => {
15
- throwKoaError(ctx, 404, 'Error not found');
16
- });
17
- const response = await request.get('/');
18
- expect(response).toMatchObject({
19
- status: 404,
20
- data: {
21
- statusCode: 404,
22
- error: 'Not Found',
23
- message: 'Error not found',
24
- },
25
- });
26
- });
27
- it('should rethrow non-Koa errors', async () => {
28
- app.silent = true;
29
- const error = new Error('This is a test error');
30
- let result;
31
- app.use(() => {
32
- throw error;
33
- });
34
- app.on('error', (err) => {
35
- result = err;
36
- });
37
- await request.get('/');
38
- expect(result).toBe(error);
39
- });
40
- it('should set Koa headers correctly', async () => {
41
- app.use((ctx) => {
42
- ctx.set('www-authenticate', 'Basic realm="Access to test data", charset="UTF-8"');
43
- throwKoaError(ctx, 401, 'Not authorized!');
44
- });
45
- const response = await request.get('/');
46
- expect(response).toMatchObject({
47
- status: 401,
48
- headers: expect.objectContaining({
49
- 'www-authenticate': 'Basic realm="Access to test data", charset="UTF-8"',
50
- }),
51
- data: {
52
- statusCode: 401,
53
- error: 'Unauthorized',
54
- message: 'Not authorized!',
55
- },
56
- });
57
- });
58
- });
59
- //# sourceMappingURL=error.test.js.map
@@ -1 +0,0 @@
1
- export {};
@@ -1,120 +0,0 @@
1
- import { logger, loggerMiddleware } from '@appsemble/node-utils';
2
- import { request, setTestApp } from 'axios-test-instance';
3
- import chalk from 'chalk';
4
- import Koa from 'koa';
5
- import { beforeEach, expect, it, vi } from 'vitest';
6
- class TestError extends Error {
7
- constructor(message) {
8
- super(message);
9
- this.name = 'TestError';
10
- }
11
- }
12
- let app;
13
- beforeEach(async () => {
14
- vi.spyOn(logger, 'info').mockImplementation(() => logger);
15
- vi.spyOn(logger, 'log').mockImplementation(() => logger);
16
- vi.useFakeTimers();
17
- app = new Koa();
18
- app.use(async (ctx, next) => {
19
- Object.defineProperty(ctx.request, 'origin', {
20
- value: 'https://example.com:1337',
21
- });
22
- try {
23
- await next();
24
- }
25
- catch (error) {
26
- if (!(error instanceof TestError)) {
27
- throw error;
28
- }
29
- ctx.status = 400;
30
- }
31
- });
32
- app.use(loggerMiddleware());
33
- app.silent = true;
34
- request.defaults.maxRedirects = 0;
35
- await setTestApp(app);
36
- });
37
- it('should log requests', async () => {
38
- await request.get('/pizza');
39
- expect(logger.info).toHaveBeenCalledWith(`${chalk.bold('GET')} https://example.com:1337/pizza — ${chalk.white('127.0.0.1')}`);
40
- });
41
- it('should log success responses as info', async () => {
42
- app.use((ctx) => {
43
- vi.advanceTimersByTime(1);
44
- ctx.status = 200;
45
- });
46
- await request.get('/fries');
47
- expect(logger.log).toHaveBeenCalledWith('info', `${chalk.bold('GET')} https://example.com:1337/fries ${chalk.green('200 OK')} ${chalk.green('1ms')}`);
48
- });
49
- it('should log redirect responses as info', async () => {
50
- app.use((ctx) => {
51
- vi.advanceTimersByTime(33);
52
- ctx.redirect('/');
53
- });
54
- await request.get('/fries');
55
- expect(logger.log).toHaveBeenCalledWith('info', `${chalk.bold('GET')} https://example.com:1337/fries ${chalk.cyan('302 Found → /')} ${chalk.green('33ms')}`);
56
- });
57
- it('should log bad responses as warn', async () => {
58
- app.use((ctx) => {
59
- vi.advanceTimersByTime(3);
60
- ctx.status = 400;
61
- });
62
- await request.get('/burrito');
63
- expect(logger.log).toHaveBeenCalledWith('warn', `${chalk.bold('GET')} https://example.com:1337/burrito ${chalk.yellow('400 Bad Request')} ${chalk.green('3ms')}`);
64
- });
65
- it('should log error responses as error', async () => {
66
- app.use((ctx) => {
67
- vi.advanceTimersByTime(53);
68
- ctx.status = 503;
69
- });
70
- await request.get('/wrap');
71
- expect(logger.log).toHaveBeenCalledWith('error', `${chalk.bold('GET')} https://example.com:1337/wrap ${chalk.red('503 Service Unavailable')} ${chalk.green('53ms')}`);
72
- });
73
- it('should log long request lengths yellow', async () => {
74
- app.use((ctx) => {
75
- vi.advanceTimersByTime(400);
76
- ctx.status = 200;
77
- });
78
- await request.get('/banana');
79
- expect(logger.log).toHaveBeenCalledWith('info', `${chalk.bold('GET')} https://example.com:1337/banana ${chalk.green('200 OK')} ${chalk.yellow('400ms')}`);
80
- });
81
- it('should log extremely long request lengths red', async () => {
82
- app.use((ctx) => {
83
- vi.advanceTimersByTime(1337);
84
- ctx.status = 200;
85
- });
86
- await request.get('/pepperoni');
87
- expect(logger.log).toHaveBeenCalledWith('info', `${chalk.bold('GET')} https://example.com:1337/pepperoni ${chalk.green('200 OK')} ${chalk.red('1337ms')}`);
88
- });
89
- it('should log errors as internal server errors and rethrow', async () => {
90
- const spy = vi.fn();
91
- const error = new Error('fail');
92
- let context;
93
- app.on('error', spy);
94
- app.use((ctx) => {
95
- vi.advanceTimersByTime(86);
96
- context = ctx;
97
- throw error;
98
- });
99
- await request.get('/taco');
100
- expect(spy).toHaveBeenCalledWith(error, context);
101
- expect(logger.log).toHaveBeenCalledWith('error', `${chalk.bold('GET')} https://example.com:1337/taco ${chalk.red('500 Internal Server Error')} ${chalk.green('86ms')}`);
102
- });
103
- it('should append the response length if it is defined', async () => {
104
- app.use((ctx) => {
105
- vi.advanceTimersByTime(1);
106
- ctx.status = 200;
107
- ctx.body = '{}';
108
- });
109
- await request.get('/fries');
110
- expect(logger.log).toHaveBeenCalledWith('info', `${chalk.bold('GET')} https://example.com:1337/fries ${chalk.green('200 OK')} ${chalk.green('1ms')}`);
111
- });
112
- it('should log handled errors correctly', async () => {
113
- app.use(() => {
114
- vi.advanceTimersByTime(15);
115
- throw new TestError();
116
- });
117
- await request.get('potatoes');
118
- expect(logger.log).toHaveBeenCalledWith('warn', `${chalk.bold('GET')} https://example.com:1337/potatoes ${chalk.yellow('400 Bad Request')} ${chalk.green('15ms')}`);
119
- });
120
- //# sourceMappingURL=loggerMiddleware.test.js.map
@@ -1 +0,0 @@
1
- export {};
@@ -1,12 +0,0 @@
1
- import { expect, it } from 'vitest';
2
- import { readFileOrString } from './readFileOrString.js';
3
- import { resolveFixture } from './testFixtures.js';
4
- it('should return file content if it resolves to a file', async () => {
5
- const result = await readFileOrString(resolveFixture('hello.txt'));
6
- expect(Buffer.from('Hello world!\n').equals(result)).toBe(true);
7
- });
8
- it('should return the input if it doesn’t resolve to a file', async () => {
9
- const result = await readFileOrString('hello.txt');
10
- expect(result).toBe('hello.txt');
11
- });
12
- //# sourceMappingURL=readFileOrString.test.js.map