> {}
65 |
66 | export interface SearchResult {
67 | description: string;
68 | name: string;
69 | score: number;
70 | url: string;
71 | version: string;
72 | }
73 |
--------------------------------------------------------------------------------
/server/types/global.types.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-type-alias */
2 |
3 | export type SearchResponse = {
4 | name: string;
5 | version: string;
6 | score: number;
7 | updated: string;
8 | repository?: string;
9 | homepage?: string;
10 | npm?: string;
11 | description: string;
12 | }[];
13 |
14 | export interface ExplorerRequest {
15 | path?: string;
16 | }
17 |
18 | export interface FileOrFolder {
19 | name: string;
20 | isDirectory: boolean;
21 | isProject: boolean;
22 | }
23 |
24 | export interface ExplorerResponse {
25 | ls: FileOrFolder[];
26 | path: string;
27 | changed: boolean;
28 | }
29 |
30 | export interface AvailableManagerResponse {
31 | npm: boolean;
32 | yarn: boolean;
33 | pnpm: boolean;
34 | }
35 |
--------------------------------------------------------------------------------
/server/types/new-server.types.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-type-alias */
2 | import type { Manager } from './dependency.types';
3 |
4 | export type MiddlewareFunction = (requestData: {
5 | params: P;
6 | extraParams: Record;
7 | }) => Record;
8 |
9 | export type ResponserFunction<
10 | B = unknown,
11 | P = unknown,
12 | R = unknown,
13 | > = (requestData: {
14 | params: P;
15 | extraParams: {
16 | projectPathDecoded: string;
17 | manager: Manager;
18 | xCacheId: string;
19 | };
20 | body: B;
21 | }) => Promise | R;
22 |
--------------------------------------------------------------------------------
/server/types/pnpm.types.ts:
--------------------------------------------------------------------------------
1 | export interface OutdatedBodyPNPM {
2 | current: string;
3 | wanted: string;
4 | latest: string;
5 | }
6 |
7 | export type OutdatedPNPM = string;
8 |
9 | interface InstalledBodyBase {
10 | version: string;
11 | }
12 |
13 | // interface InstalledBodyMissing {
14 | // required: string;
15 | // missing: boolean;
16 | // }
17 |
18 | // interface InstalledBodyExtra {
19 | // version: string;
20 | // extraneous?: boolean;
21 | // }
22 |
23 | export type InstalledBodyPNPM = InstalledBodyBase; // | InstalledBodyExtra | InstalledBodyMissing;
24 |
25 | export type InstalledPNPM = [
26 | {
27 | devDependencies?: Record;
28 | dependencies?: Record;
29 | },
30 | ];
31 |
--------------------------------------------------------------------------------
/server/types/yarn.types.ts:
--------------------------------------------------------------------------------
1 | interface InstalledBase {
2 | data: {
3 | trees: [
4 | {
5 | name: string;
6 | },
7 | ];
8 | };
9 | }
10 |
11 | export type InstalledYarn = InstalledBase;
12 |
13 | export interface OutdatedYarn {
14 | data?: {
15 | head: string[];
16 | body: string[][];
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/server/utils/cache.ts:
--------------------------------------------------------------------------------
1 | import type { DependencyInstalled } from '../types/dependency.types';
2 | import { ONE, ZERO } from './utils';
3 |
4 | type CacheValue = DependencyInstalled[] | undefined;
5 |
6 | let cache: Record = {};
7 |
8 | export const getFromCache = (name: string): CacheValue => {
9 | return cache[name];
10 | };
11 |
12 | export const putToCache = (name: string, data?: CacheValue): void => {
13 | cache[name] = data;
14 | };
15 |
16 | export const updateInCache = (
17 | name: string,
18 | dependency: DependencyInstalled,
19 | ): void => {
20 | const myCache = cache[name];
21 | if (myCache) {
22 | const indexToUpdate = myCache.findIndex(
23 | (item) => dependency.name === item.name,
24 | );
25 |
26 | if (indexToUpdate >= ZERO) {
27 | myCache[indexToUpdate] = dependency;
28 | } else {
29 | myCache.push(dependency);
30 | }
31 | }
32 | };
33 |
34 | export const spliceFromCache = (name: string, dependencyName: string): void => {
35 | const myCache = cache[name];
36 |
37 | if (myCache) {
38 | const indexToSplice = myCache.findIndex(
39 | (item) => dependencyName === item.name,
40 | );
41 |
42 | if (indexToSplice >= ZERO) {
43 | myCache.splice(indexToSplice, ONE);
44 | }
45 | }
46 | };
47 |
48 | export const clearCache = (name?: string): void => {
49 | if (name === undefined) {
50 | cache = {};
51 | } else {
52 | putToCache(name);
53 | }
54 | };
55 |
--------------------------------------------------------------------------------
/server/utils/delete-folder-resursive.ts:
--------------------------------------------------------------------------------
1 | import { existsSync, lstatSync, readdirSync, rmdirSync, unlinkSync } from 'fs';
2 |
3 | export const deleteFolderRecursive = (rmPath: string): void => {
4 | let files = [];
5 | if (existsSync(rmPath)) {
6 | files = readdirSync(rmPath);
7 | for (const [, file] of files.entries()) {
8 | const currentPath = `${rmPath}/${file}`;
9 | if (lstatSync(currentPath).isDirectory()) {
10 | // recurse
11 | deleteFolderRecursive(currentPath);
12 | } else {
13 | // delete file
14 | unlinkSync(currentPath);
15 | }
16 | }
17 | rmdirSync(rmPath);
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/server/utils/get-project-package-json.ts:
--------------------------------------------------------------------------------
1 | import { existsSync, readFileSync } from 'fs';
2 | import path from 'path';
3 |
4 | import type { DependencyBase, Manager } from '../types/dependency.types';
5 | import { parseJSON } from './parse-json';
6 |
7 | interface PackageJSON {
8 | dependencies?: Record;
9 | devDependencies?: Record;
10 | }
11 |
12 | export const getProjectPackageJSON = (
13 | projectPath: string,
14 | ): PackageJSON | null => {
15 | const packageJSONpath = path.join(projectPath, 'package.json');
16 | if (existsSync(packageJSONpath)) {
17 | return parseJSON(
18 | readFileSync(packageJSONpath, { encoding: 'utf8' }),
19 | );
20 | }
21 |
22 | return null;
23 | };
24 |
25 | export const getDependenciesFromPackageJson = (
26 | projectPath: string,
27 | ): Record => {
28 | const packageJson = getProjectPackageJSON(projectPath);
29 | if (packageJson === null || !('dependencies' in packageJson)) {
30 | return {};
31 | }
32 | return packageJson.dependencies ?? {};
33 | };
34 |
35 | export const getDevelopmentDependenciesFromPackageJson = (
36 | projectPath: string,
37 | ): Record => {
38 | const packageJson = getProjectPackageJSON(projectPath);
39 | if (packageJson === null || !('devDependencies' in packageJson)) {
40 | return {};
41 | }
42 | return packageJson.devDependencies ?? {};
43 | };
44 |
45 | export const getAllDependenciesFromPackageJsonAsArray = (
46 | projectPath: string,
47 | manager: Manager,
48 | ): DependencyBase[] => {
49 | const dependencies = getDependenciesFromPackageJson(projectPath);
50 | const devDependencies =
51 | getDevelopmentDependenciesFromPackageJson(projectPath);
52 |
53 | return [
54 | ...Object.entries(dependencies).map(
55 | ([name, required]): DependencyBase => ({
56 | manager,
57 | name,
58 | type: 'prod',
59 | required,
60 | }),
61 | ),
62 | ...Object.entries(devDependencies).map(
63 | ([name, required]): DependencyBase => ({
64 | manager,
65 | name,
66 | type: 'dev',
67 | required,
68 | }),
69 | ),
70 | ];
71 | };
72 |
73 | export const getTypeFromPackageJson = (
74 | projectPath: string,
75 | dependencyName: string,
76 | ): 'dev' | 'extraneous' | 'prod' => {
77 | const packageJson = getProjectPackageJSON(projectPath);
78 | if (packageJson === null) {
79 | console.log('ERROR????');
80 | return 'extraneous';
81 | }
82 |
83 | const { dependencies, devDependencies } = packageJson;
84 |
85 | if (dependencies && dependencyName in dependencies) {
86 | return 'prod';
87 | }
88 |
89 | if (devDependencies && dependencyName in devDependencies) {
90 | return 'dev';
91 | }
92 |
93 | return 'extraneous';
94 | };
95 |
96 | export const getRequiredFromPackageJson = (
97 | projectPath: string,
98 | dependencyName: string,
99 | ): string | undefined => {
100 | const packageJson = getProjectPackageJSON(projectPath);
101 | if (packageJson === null) {
102 | return undefined;
103 | }
104 |
105 | const { dependencies, devDependencies } = packageJson;
106 |
107 | if (dependencies && dependencyName in dependencies) {
108 | return dependencies[dependencyName];
109 | }
110 |
111 | if (devDependencies && dependencyName in devDependencies) {
112 | return devDependencies[dependencyName];
113 | }
114 |
115 | return undefined;
116 | };
117 |
--------------------------------------------------------------------------------
/server/utils/map-dependencies.ts:
--------------------------------------------------------------------------------
1 | import type { InstalledBody } from '../types/commands.types';
2 |
3 | export const uniqueOrNull = (
4 | value: string | undefined,
5 | comparision: (string | null | undefined)[],
6 | ): string | null => {
7 | if (value === undefined) {
8 | return null;
9 | }
10 |
11 | return comparision.includes(value) ? null : value;
12 | };
13 |
14 | // eslint-disable-next-line max-statements
15 | export const getInstalledVersion = (
16 | installed?: InstalledBody,
17 | ): string | null => {
18 | if (!installed) {
19 | return null;
20 | }
21 |
22 | if ('version' in installed) {
23 | return installed.version;
24 | }
25 |
26 | if ('invalid' in installed) {
27 | return null;
28 | }
29 |
30 | if ('missing' in installed) {
31 | return null;
32 | }
33 |
34 | if ('extraneous' in installed) {
35 | return null;
36 | }
37 |
38 | if (!('required' in installed)) {
39 | return null;
40 | }
41 |
42 | if (typeof installed.required === 'string') {
43 | return null;
44 | }
45 |
46 | // TODO peerMissing ERROR HERE
47 | return installed.required.version;
48 | };
49 |
50 | export const getWantedVersion = (
51 | installed: string | null | undefined,
52 | outdated?: { wanted?: string; latest?: string },
53 | ): string | null => {
54 | if (installed === null || !outdated) {
55 | return null;
56 | }
57 |
58 | return uniqueOrNull(outdated.wanted, [installed]);
59 | };
60 |
61 | export const getLatestVersion = (
62 | installed: string | null | undefined,
63 | wanted: string | null | undefined,
64 | outdated?: { wanted?: string; latest?: string },
65 | ): string | null => {
66 | if (installed === null || !outdated) {
67 | return null;
68 | }
69 |
70 | return uniqueOrNull(outdated.latest, [installed, wanted]);
71 | };
72 |
--------------------------------------------------------------------------------
/server/utils/parse-json.ts:
--------------------------------------------------------------------------------
1 | export const parseJSON = (stringToParse: string): T | null => {
2 | let result = null;
3 | try {
4 | result = JSON.parse(stringToParse) as T;
5 | } catch {
6 | // eslint-disable-next-line no-console
7 | console.error('JSON error', stringToParse, '#');
8 | return null;
9 | }
10 |
11 | return result;
12 | };
13 |
--------------------------------------------------------------------------------
/server/utils/request-with-promise.ts:
--------------------------------------------------------------------------------
1 | import type { ClientRequestArgs } from 'http';
2 | import https from 'https';
3 |
4 | export const requestGET = (hostname: string, path: string): Promise => {
5 | return new Promise((resolve, reject) => {
6 | const options: ClientRequestArgs = {
7 | hostname,
8 | port: 443,
9 | path: encodeURI(path),
10 | method: 'GET',
11 | headers: {
12 | // eslint-disable-next-line @typescript-eslint/naming-convention
13 | 'User-Agent': 'npm-gui',
14 | },
15 | };
16 |
17 | const request = https.request(options, (response) => {
18 | let responseData = '';
19 |
20 | response.on('data', (data) => {
21 | responseData += data.toString();
22 | });
23 | response.on('end', () => {
24 | resolve(responseData);
25 | });
26 | });
27 |
28 | request.on('error', (error) => {
29 | reject(error);
30 | });
31 |
32 | request.end();
33 | });
34 | };
35 |
--------------------------------------------------------------------------------
/server/utils/simple-cross-spawn.ts:
--------------------------------------------------------------------------------
1 | import type { ChildProcess, SpawnOptionsWithoutStdio } from 'child_process';
2 | import { spawn as cpSpawn } from 'child_process';
3 |
4 | const metaCharsRegExp = /([ !"%&()*,;<>?[\]^`|])/g;
5 |
6 | export const spawn = (
7 | command: string,
8 | arguments_?: readonly string[],
9 | options?: SpawnOptionsWithoutStdio,
10 | ): ChildProcess => {
11 | if (process.platform !== 'win32') {
12 | return cpSpawn(command, arguments_, options);
13 | }
14 |
15 | const shellCommand = [
16 | command,
17 | ...(arguments_ || []).map((argument) =>
18 | `"${argument}"`.replace(metaCharsRegExp, '^$1'),
19 | ),
20 | ].join(' ');
21 |
22 | return cpSpawn(
23 | process.env['comspec'] || 'cmd.exe',
24 | ['/d', '/s', '/c', `"${shellCommand}"`],
25 | {
26 | ...options,
27 | windowsVerbatimArguments: true,
28 | },
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/server/utils/utils.ts:
--------------------------------------------------------------------------------
1 | export const ZERO = 0;
2 | export const ONE = 1;
3 |
4 | export const HTTP_STATUS_OK = 200;
5 | export const HTTP_STATUS_BAD_REQUEST = 400;
6 | export const HTTP_STATUS_NOT_FOUND = 404;
7 |
8 | export const notEmpty = (
9 | value: TValue | null | undefined,
10 | ): value is TValue => {
11 | return value !== null && value !== undefined;
12 | };
13 |
--------------------------------------------------------------------------------
/tests/add-multiple.test.ts:
--------------------------------------------------------------------------------
1 | import { HTTP_STATUS_BAD_REQUEST, HTTP_STATUS_OK } from '../server/utils/utils';
2 | import type { TestProject } from './tests-utils';
3 | import {
4 | dependencyTypes,
5 | managers,
6 | prepareTestProject,
7 | TEST,
8 | } from './tests-utils';
9 |
10 | describe.each(dependencyTypes)(
11 | 'add multiple dependencies as %s',
12 | (dependencyType) => {
13 | describe.each(managers)('%s', (manager) => {
14 | // eslint-disable-next-line @typescript-eslint/init-declarations
15 | let project: TestProject;
16 |
17 | beforeAll(async () => {
18 | project = await prepareTestProject('add-multiple', manager);
19 | });
20 |
21 | test('invalid name', async () => {
22 | await project.prepareClear({});
23 |
24 | const response = await project.requestAdd(dependencyType, [
25 | { name: 'sdmvladbf3', version: 'v1.0.0' },
26 | { name: 'fasdf2', version: 'v1.0.0' },
27 | ]);
28 | expect(response.status).toBe(HTTP_STATUS_BAD_REQUEST);
29 |
30 | const fastResponse = await project.requestGetFast();
31 | const fullResponse = await project.requestGetFull();
32 |
33 | expect(fastResponse.body).toEqual([]);
34 | expect(fullResponse.body).toEqual([]);
35 | });
36 |
37 | test('invalid version', async () => {
38 | await project.prepareClear({});
39 |
40 | const response = await project.requestAdd(dependencyType, [
41 | { name: 'npm-gui-tests', version: 'v3.0.0' },
42 | { name: 'npm-gui-tests-2', version: 'v15.0.0' },
43 | ]);
44 | expect(response.status).toBe(HTTP_STATUS_BAD_REQUEST);
45 |
46 | const fastResponse = await project.requestGetFast();
47 | const fullResponse = await project.requestGetFull();
48 |
49 | expect(fastResponse.body).toEqual([]);
50 | expect(fullResponse.body).toEqual([]);
51 | });
52 |
53 | test('correct dependency, no version', async () => {
54 | await project.prepareClear({});
55 |
56 | const response = await project.requestAdd(dependencyType, [
57 | { name: 'npm-gui-tests' },
58 | { name: 'npm-gui-tests-2' },
59 | ]);
60 | expect(response.status).toBe(HTTP_STATUS_OK);
61 |
62 | const fastResponse = await project.requestGetFast();
63 | const fullResponse = await project.requestGetFull();
64 |
65 | expect(fastResponse.body).toIncludeAllMembers([
66 | {
67 | ...TEST[manager].PKG_A_UP,
68 | required: '^2.1.1',
69 | type: dependencyType,
70 | },
71 | {
72 | ...TEST[manager].PKG_B_UP,
73 | required: '^1.0.1',
74 | type: dependencyType,
75 | },
76 | ]);
77 |
78 | expect(fullResponse.body).toIncludeAllMembers([
79 | { ...TEST[manager].PKG_A_UP_NEWEST, type: dependencyType },
80 | { ...TEST[manager].PKG_B_UP_NEWEST, type: dependencyType },
81 | ]);
82 | });
83 |
84 | test('correct dependency, with version', async () => {
85 | await project.prepareClear({});
86 |
87 | const response = await project.requestAdd(dependencyType, [
88 | { name: 'npm-gui-tests', version: '^1.0.0' },
89 | { name: 'npm-gui-tests-2', version: '^1.0.0' },
90 | ]);
91 | expect(response.status).toBe(HTTP_STATUS_OK);
92 |
93 | const fastResponse = await project.requestGetFast();
94 | const fullResponse = await project.requestGetFull();
95 |
96 | expect(fastResponse.body).toIncludeAllMembers([
97 | { ...TEST[manager].PKG_A_UP, type: dependencyType },
98 | { ...TEST[manager].PKG_B_UP, type: dependencyType },
99 | ]);
100 | expect(fullResponse.body).toIncludeAllMembers([
101 | { ...TEST[manager].PKG_A_UP_INSTALLED, type: dependencyType },
102 | { ...TEST[manager].PKG_B_UP_INSTALLED, type: dependencyType },
103 | ]);
104 | });
105 | });
106 | },
107 | );
108 |
--------------------------------------------------------------------------------
/tests/add-single.test.ts:
--------------------------------------------------------------------------------
1 | import { HTTP_STATUS_OK } from '../server/utils/utils';
2 | import type { TestProject } from './tests-utils';
3 | import {
4 | dependencyTypes,
5 | managers,
6 | prepareTestProject,
7 | TEST,
8 | } from './tests-utils';
9 |
10 | describe.each(dependencyTypes)('add single %s depednency', (dependencyType) => {
11 | describe.each(managers)('as %s', (manager) => {
12 | // eslint-disable-next-line @typescript-eslint/init-declarations
13 | let project: TestProject;
14 |
15 | beforeAll(async () => {
16 | project = await prepareTestProject('add-single', manager);
17 | });
18 |
19 | test('invalid name', async () => {
20 | await project.prepareClear({});
21 |
22 | const response = await project.requestAdd(dependencyType, [
23 | { name: 'sdmvladbf3', version: 'v1.0.0' },
24 | ]);
25 | expect(response.status).not.toBe(HTTP_STATUS_OK);
26 |
27 | const fastResponse = await project.requestGetFast();
28 | const fullResponse = await project.requestGetFull();
29 |
30 | expect(fastResponse.body).toEqual([]);
31 | expect(fullResponse.body).toEqual([]);
32 | });
33 |
34 | test('invalid version', async () => {
35 | await project.prepareClear({});
36 |
37 | const response = await project.requestAdd(dependencyType, [
38 | { name: 'npm-gui-tests', version: 'v3.0.0' },
39 | ]);
40 | expect(response.status).not.toBe(HTTP_STATUS_OK);
41 |
42 | const fastResponse = await project.requestGetFast();
43 | const fullResponse = await project.requestGetFull();
44 |
45 | expect(fastResponse.body).toEqual([]);
46 | expect(fullResponse.body).toEqual([]);
47 | });
48 |
49 | test('correct dependency, no version', async () => {
50 | await project.prepareClear({});
51 |
52 | const response = await project.requestAdd(dependencyType, [
53 | { name: 'npm-gui-tests' },
54 | ]);
55 | expect(response.status).toBe(HTTP_STATUS_OK);
56 |
57 | const fastResponse = await project.requestGetFast();
58 | const fullResponse = await project.requestGetFull();
59 |
60 | expect(fastResponse.body).toPartiallyContain({
61 | ...TEST[manager].PKG_A,
62 | required: '^2.1.1',
63 | type: dependencyType,
64 | });
65 | expect(fullResponse.body).toPartiallyContain({
66 | ...TEST[manager].PKG_A_UP_NEWEST,
67 | type: dependencyType,
68 | });
69 | });
70 |
71 | test('correct dependency, with version', async () => {
72 | await project.prepareClear({});
73 |
74 | const response = await project.requestAdd(dependencyType, [
75 | { name: 'npm-gui-tests', version: '^1.0.0' },
76 | ]);
77 | expect(response.status).toBe(HTTP_STATUS_OK);
78 |
79 | const fastResponse = await project.requestGetFast();
80 | const fullResponse = await project.requestGetFull();
81 |
82 | expect(fastResponse.body).toPartiallyContain({
83 | ...TEST[manager].PKG_A_UP,
84 | type: dependencyType,
85 | });
86 | expect(fullResponse.body).toPartiallyContain({
87 | ...TEST[manager].PKG_A_UP_INSTALLED,
88 | type: dependencyType,
89 | });
90 | });
91 | });
92 | });
93 |
--------------------------------------------------------------------------------
/tests/cache.test.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-statements */
2 | import type api from 'supertest';
3 |
4 | import { HTTP_STATUS_OK } from '../server/utils/utils';
5 | import type { TestProject } from './tests-utils';
6 | import { managers, prepareTestProject, TEST } from './tests-utils';
7 |
8 | const withTimeExecution = async (
9 | callback: () => Promise,
10 | ): Promise<[number, T]> => {
11 | const start = Date.now();
12 | const returnValue = await callback();
13 | const executionTime = Date.now() - start;
14 |
15 | return [executionTime, returnValue];
16 | };
17 |
18 | describe.each(managers)('%s cache fetching', (manager) => {
19 | // eslint-disable-next-line @typescript-eslint/init-declarations
20 | let project: TestProject;
21 |
22 | beforeAll(async () => {
23 | project = await prepareTestProject('cache', manager);
24 | });
25 |
26 | test('next full response calls should be faster than first', async () => {
27 | await project.prepareClear({
28 | dependencies: {
29 | 'npm-gui-tests': '^1.0.0',
30 | 'npm-gui-tests-2': '^1.0.0',
31 | },
32 | install: true,
33 | });
34 |
35 | const [executionTime1] = await withTimeExecution(
36 | async () => await project.requestGetFull(),
37 | );
38 | expect(executionTime1).toBeGreaterThan(100);
39 |
40 | const [executionTime2] = await withTimeExecution(
41 | async () => await project.requestGetFull(),
42 | );
43 | expect(executionTime2).toBeLessThan(100);
44 |
45 | const [executionTime3] = await withTimeExecution(
46 | async () => await project.requestGetFull(),
47 | );
48 | expect(executionTime3).toBeLessThan(100);
49 |
50 | expect(executionTime2).toBeLessThan(executionTime1);
51 | expect(executionTime3).toBeLessThan(executionTime1);
52 | });
53 |
54 | test('cache update on add/delete dependency', async () => {
55 | await project.prepareClear({
56 | dependencies: {
57 | 'npm-gui-tests': '^1.0.0',
58 | },
59 | install: true,
60 | });
61 |
62 | // create cache request
63 | const response0 = await project.requestGetFull();
64 | expect(response0.status).toBe(HTTP_STATUS_OK);
65 | expect(response0.body).toIncludeAllMembers([TEST[manager].PKG_A_INSTALLED]);
66 |
67 | // update cache request (new dependency)
68 | const response1 = await project.requestAdd('prod', [
69 | { name: 'npm-gui-tests-2', version: '^1.0.0' },
70 | ]);
71 | expect(response1.status).toBe(HTTP_STATUS_OK);
72 |
73 | // listing
74 | const [executionTime1, full1] = await withTimeExecution(
75 | async () => await project.requestGetFull(),
76 | );
77 | expect(executionTime1).toBeLessThan(100);
78 | expect(full1.body).toIncludeAllMembers([
79 | TEST[manager].PKG_A_INSTALLED,
80 | TEST[manager].PKG_B_UP_INSTALLED,
81 | ]);
82 |
83 | // update cache request (already installed dependency)
84 | const response3 = await project.requestAdd('prod', [
85 | { name: 'npm-gui-tests', version: '^2.1.1' },
86 | ]);
87 | expect(response3.status).toBe(HTTP_STATUS_OK);
88 |
89 | // listing
90 | const [executionTime2, full2] = await withTimeExecution(
91 | async () => await project.requestGetFull(),
92 | );
93 | expect(executionTime2).toBeLessThan(100);
94 | expect(full2.body).toIncludeAllMembers([
95 | TEST[manager].PKG_A_UP_NEWEST,
96 | TEST[manager].PKG_B_UP_INSTALLED,
97 | ]);
98 |
99 | // update cache request (remove installed dependency)
100 | const response2 = await project.requestDel('prod', [
101 | { name: 'npm-gui-tests' },
102 | ]);
103 | expect(response2.status).toBe(HTTP_STATUS_OK);
104 |
105 | // listing
106 | const [executionTime3, full3] = await withTimeExecution(
107 | async () => await project.requestGetFull(),
108 | );
109 | expect(executionTime3).toBeLessThan(100);
110 | expect(full3.body).toIncludeAllMembers([TEST[manager].PKG_B_UP_INSTALLED]);
111 | expect(full3.body).toHaveLength(1);
112 |
113 | // update cache request (remove unknown dependency)
114 | const response4 = await project.requestDel('prod', [
115 | { name: 'asdfasdfasdf' },
116 | ]);
117 | expect(response4.status).toBe(HTTP_STATUS_OK);
118 | });
119 | });
120 |
--------------------------------------------------------------------------------
/tests/comparators.test.ts:
--------------------------------------------------------------------------------
1 | import type { TestProject } from './tests-utils';
2 | import { managers, prepareTestProject } from './tests-utils';
3 |
4 | describe.each(managers)('%s comparators', (manager) => {
5 | describe.each([
6 | { required: '*', installed: '2.1.1', latest: null, wanted: null },
7 | { required: '1', installed: '1.1.1', latest: '2.1.1', wanted: null },
8 | { required: '1.*', installed: '1.1.1', latest: '2.1.1', wanted: null },
9 | { required: '1.0.0', installed: '1.0.0', latest: '2.1.1', wanted: null },
10 | {
11 | required: 'v1.0.0',
12 | installed: '1.0.0',
13 | latest: '2.1.1',
14 | wanted: null,
15 | },
16 | {
17 | required: '=1.0.0',
18 | installed: '1.0.0',
19 | latest: '2.1.1',
20 | wanted: null,
21 | },
22 | {
23 | required: '^1.0.0',
24 | installed: '1.1.1',
25 | latest: '2.1.1',
26 | wanted: null,
27 | },
28 | { required: '>=1.0.0', installed: '2.1.1', latest: null, wanted: null },
29 | {
30 | required: '~1.0.0',
31 | installed: '1.0.1',
32 | latest: '2.1.1',
33 | wanted: null,
34 | },
35 | {
36 | required: '>=1.0.0 < 2.0.0',
37 | installed: '1.1.1',
38 | latest: '2.1.1',
39 | wanted: null,
40 | },
41 | {
42 | required: '1.0.0 - 2.0.0',
43 | installed: '2.0.0',
44 | latest: '2.1.1',
45 | wanted: null,
46 | },
47 | // '1.0.0-beta.1',
48 | ])('%s', ({ required, installed, wanted, latest }) => {
49 | // eslint-disable-next-line @typescript-eslint/init-declarations
50 | let project: TestProject;
51 |
52 | beforeAll(async () => {
53 | project = await prepareTestProject('comparators', manager);
54 | });
55 |
56 | test('uninstalled', async () => {
57 | await project.prepareClear({
58 | dependencies: { 'npm-gui-tests': required },
59 | });
60 |
61 | const fastResponse = await project.requestGetFast();
62 | const fullResponse = await project.requestGetFull();
63 |
64 | expect(fastResponse.body).toIncludeAllMembers([
65 | {
66 | manager,
67 | name: 'npm-gui-tests',
68 | required,
69 | type: 'prod',
70 | },
71 | ]);
72 |
73 | expect(fullResponse.body).toIncludeAllMembers([
74 | {
75 | manager,
76 | name: 'npm-gui-tests',
77 | required,
78 | installed: null,
79 | latest: null,
80 | wanted: null,
81 | type: 'prod',
82 | },
83 | ]);
84 | });
85 |
86 | test('installed', async () => {
87 | await project.prepareClear({
88 | dependencies: { 'npm-gui-tests': required },
89 | install: true,
90 | });
91 |
92 | const fastResponse = await project.requestGetFast();
93 | const fullResponse = await project.requestGetFull();
94 |
95 | expect(fastResponse.body).toIncludeAllMembers([
96 | {
97 | manager,
98 | name: 'npm-gui-tests',
99 | required,
100 | type: 'prod',
101 | },
102 | ]);
103 |
104 | expect(fullResponse.body).toIncludeAllMembers([
105 | {
106 | manager,
107 | name: 'npm-gui-tests',
108 | required,
109 | installed,
110 | latest,
111 | wanted,
112 | type: 'prod',
113 | },
114 | ]);
115 | });
116 | });
117 | });
118 |
--------------------------------------------------------------------------------
/tests/delete.test.ts:
--------------------------------------------------------------------------------
1 | import { HTTP_STATUS_OK } from '../server/utils/utils';
2 | import type { TestProject } from './tests-utils';
3 | import { managers, prepareTestProject, TEST } from './tests-utils';
4 |
5 | describe.each(managers)('%s install', (manager) => {
6 | // eslint-disable-next-line @typescript-eslint/init-declarations
7 | let project: TestProject;
8 |
9 | beforeAll(async () => {
10 | project = await prepareTestProject('delete', manager);
11 | });
12 |
13 | test('uninstalled invalid name', async () => {
14 | await project.prepareClear({
15 | dependencies: { 'npm-gui-tests': '^1.0.0' },
16 | });
17 |
18 | const response = await project.requestDel('prod', [{ name: 'sdmvladbf3' }]);
19 | expect(response.status).toBe(HTTP_STATUS_OK);
20 |
21 | const fastResponse = await project.requestGetFast();
22 |
23 | expect(fastResponse.body).toPartiallyContain(TEST[manager].PKG_A);
24 | });
25 |
26 | test('uninstalled valid name', async () => {
27 | await project.prepareClear({
28 | dependencies: { 'npm-gui-tests': '^1.0.0' },
29 | });
30 |
31 | const response = await project.requestDel('prod', [
32 | { name: 'npm-gui-tests' },
33 | ]);
34 | expect(response.status).toBe(HTTP_STATUS_OK);
35 |
36 | const fastResponse = await project.requestGetFast();
37 | const fullResponse = await project.requestGetFull();
38 |
39 | expect(fastResponse.body).toEqual([]);
40 | expect(fullResponse.body).toEqual([]);
41 | });
42 |
43 | test('installed valid name', async () => {
44 | await project.prepareClear({
45 | dependencies: { 'npm-gui-tests': '^1.0.0' },
46 | install: true,
47 | });
48 | const fastResponseBefore = await project.requestGetFast();
49 | const fullResponseBefore = await project.requestGetFull();
50 |
51 | expect(fastResponseBefore.body).toPartiallyContain(TEST[manager].PKG_A);
52 | expect(fullResponseBefore.body).toPartiallyContain(
53 | TEST[manager].PKG_A_INSTALLED,
54 | );
55 |
56 | const response = await project.requestDel('prod', [
57 | { name: 'npm-gui-tests' },
58 | ]);
59 | expect(response.status).toBe(HTTP_STATUS_OK);
60 |
61 | const fastResponse = await project.requestGetFast();
62 | const fullResponse = await project.requestGetFull();
63 |
64 | expect(fastResponse.body).toEqual([]);
65 | expect(fullResponse.body).toEqual([]);
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/tests/explorer.test.ts:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import api from 'supertest';
3 |
4 | import { app } from '../server';
5 | import { HTTP_STATUS_OK } from '../server/utils/utils';
6 | import { encodePath, prepareTestProject } from './tests-utils';
7 |
8 | describe(`Explorer`, () => {
9 | test('should return result of pwd when given path is undefined', async () => {
10 | const project = await prepareTestProject('explorer', 'npm');
11 | await project.prepareClear({});
12 |
13 | const response = await api(app.server).get('/api/explorer/');
14 | expect(response.status).toBe(HTTP_STATUS_OK);
15 | expect(response.body.path).not.toBe(undefined);
16 |
17 | expect(response.body.ls).toPartiallyContain({
18 | isDirectory: true,
19 | isProject: false,
20 | name: 'tests',
21 | });
22 | });
23 |
24 | test('should return result when path is defined', async () => {
25 | const project = await prepareTestProject('explorer', 'yarn');
26 | await project.prepareClear({});
27 |
28 | const response = await api(app.server).get(
29 | `/api/explorer/${encodePath(
30 | path.join(__dirname, 'test-project-yarn', 'explorer'),
31 | )}`,
32 | );
33 | expect(response.status).toBe(HTTP_STATUS_OK);
34 | expect(response.body.path).not.toBe(undefined);
35 |
36 | expect(response.body.ls).toPartiallyContain({
37 | isDirectory: false,
38 | isProject: false,
39 | name: 'somefile',
40 | });
41 |
42 | expect(response.body.ls).toPartiallyContain({
43 | isDirectory: false,
44 | isProject: true,
45 | name: 'yarn.lock',
46 | });
47 |
48 | expect(response.body.ls).toPartiallyContain({
49 | isDirectory: false,
50 | isProject: true,
51 | name: 'package.json',
52 | });
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/tests/extras.test.ts:
--------------------------------------------------------------------------------
1 | import type { TestProject } from './tests-utils';
2 | import { managers, prepareTestProject } from './tests-utils';
3 |
4 | describe.each(managers)('%s extra info', (manager) => {
5 | // eslint-disable-next-line @typescript-eslint/init-declarations
6 | let project: TestProject;
7 |
8 | beforeAll(async () => {
9 | project = await prepareTestProject('extras', manager);
10 | });
11 |
12 | test('get', async () => {
13 | await project.prepareClear({
14 | dependencies: { 'npm-gui-tests': '^1.0.0' },
15 | });
16 |
17 | await project.requestInstall();
18 |
19 | const extrasResponse = await project.requestGetExtras(
20 | manager,
21 | 'npm-gui-tests@2.0.0',
22 | );
23 |
24 | expect(extrasResponse.body).toIncludeSameMembers([
25 | {
26 | created: '2018-11-01T10:54:29.810Z',
27 | homepage: 'https://github.com/q-nick/npm-gui-tests#readme',
28 | name: 'npm-gui-tests',
29 | repository: 'git+https://github.com/q-nick/npm-gui-tests.git',
30 | size: 1606,
31 | time: {
32 | '1.0.0': '2018-11-01T10:54:29.979Z',
33 | '1.0.1': '2018-11-01T10:56:06.435Z',
34 | '1.1.0': '2018-11-01T10:56:22.241Z',
35 | '1.1.1': '2018-11-01T10:56:37.871Z',
36 | '2.0.0': '2018-11-01T10:57:00.397Z',
37 | '2.0.1': '2018-11-01T10:57:11.030Z',
38 | '2.1.0': '2018-11-01T10:58:01.883Z',
39 | '2.1.1': '2018-11-01T11:07:19.996Z',
40 | created: '2018-11-01T10:54:29.810Z',
41 | modified: '2022-05-11T12:35:33.226Z',
42 | },
43 | updated: '2022-05-11T12:35:33.226Z',
44 | version: '2.0.0',
45 | versions: [
46 | '1.0.0',
47 | '1.0.1',
48 | '1.1.0',
49 | '1.1.1',
50 | '2.0.0',
51 | '2.0.1',
52 | '2.1.0',
53 | '2.1.1',
54 | ],
55 | },
56 | ]);
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/tests/global.d.ts:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line import/no-unassigned-import
2 | import 'jest-extended';
3 |
--------------------------------------------------------------------------------
/tests/global.test.ts:
--------------------------------------------------------------------------------
1 | import { spawnSync } from 'child_process';
2 | import { readJSONSync, writeJSONSync } from 'fs-extra';
3 | import path from 'path';
4 | import api from 'supertest';
5 |
6 | import { app } from '../server';
7 | import type { Basic } from '../server/types/dependency.types';
8 | import { HTTP_STATUS_OK } from '../server/utils/utils';
9 |
10 | describe('Global Packages', () => {
11 | test('install', async () => {
12 | const response = await api(app.server)
13 | .post('/api/global/dependencies')
14 | .send([{ name: 'npm-gui-tests', version: '1.0.0' }]);
15 |
16 | expect(response.status).toBe(HTTP_STATUS_OK);
17 | });
18 |
19 | test('fast listing', async () => {
20 | const response = await api(app.server).get(
21 | '/api/global/dependencies/simple',
22 | );
23 |
24 | expect(response.status).toBe(HTTP_STATUS_OK);
25 | expect(response.body).toPartiallyContain({
26 | name: 'npm-gui-tests',
27 | manager: 'npm',
28 | installed: '1.0.0',
29 | });
30 | });
31 |
32 | test('full listing', async () => {
33 | const response = await api(app.server).get('/api/global/dependencies/full');
34 |
35 | expect(response.status).toBe(HTTP_STATUS_OK);
36 | expect(response.body).toPartiallyContain({
37 | name: 'npm-gui-tests',
38 | manager: 'npm',
39 | installed: '1.0.0',
40 | latest: '2.1.1',
41 | });
42 | });
43 |
44 | test('uninstalling', async () => {
45 | const response = await api(app.server).delete(
46 | '/api/global/dependencies/global/npm-gui-tests',
47 | );
48 |
49 | expect(response.status).toBe(HTTP_STATUS_OK);
50 |
51 | const responseListing = await api(app.server).get(
52 | '/api/global/dependencies/simple',
53 | );
54 | expect(responseListing.status).toBe(HTTP_STATUS_OK);
55 | expect(
56 | responseListing.body.find((d: Basic) => d.name === 'npm-gui-tests'),
57 | ).toBe(undefined);
58 | });
59 |
60 | test('weird behavior when global package is missing its version', async () => {
61 | await api(app.server)
62 | .post('/api/global/dependencies')
63 | .send([{ name: 'npm-gui-tests', version: '1.0.0' }]);
64 |
65 | // find package.json in global folder
66 | const packageJSONPath = path.join(
67 | spawnSync('npm', ['root', '-g'], { shell: process.platform === 'win32' })
68 | .stdout.toString()
69 | .replace(/[\n\r]/gm, ''),
70 | 'npm-gui-tests',
71 | 'package.json',
72 | );
73 |
74 | // remove version from package.json
75 | const packageJSON = readJSONSync(packageJSONPath);
76 | delete packageJSON.version;
77 | writeJSONSync(packageJSONPath, packageJSON);
78 |
79 | const response = await api(app.server).get(
80 | '/api/global/dependencies/simple',
81 | );
82 |
83 | expect(response.body).toPartiallyContain({
84 | installed: null,
85 | manager: 'npm',
86 | name: 'npm-gui-tests',
87 | type: 'global',
88 | });
89 | });
90 | });
91 |
--------------------------------------------------------------------------------
/tests/info.test.ts:
--------------------------------------------------------------------------------
1 | import api from 'supertest';
2 |
3 | import { app } from '../server';
4 | import { HTTP_STATUS_OK } from '../server/utils/utils';
5 |
6 | describe.skip(`Info`, () => {
7 | test('should return 200', async () => {
8 | const response = await api(app.server).get('/api/info/unit-test');
9 |
10 | expect(response.status).toBe(HTTP_STATUS_OK);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/tests/install-force.test.ts:
--------------------------------------------------------------------------------
1 | import type { TestProject } from './tests-utils';
2 | import { managers, prepareTestProject, TEST } from './tests-utils';
3 |
4 | describe.each(managers)('%s install', (manager) => {
5 | // eslint-disable-next-line @typescript-eslint/init-declarations
6 | let project: TestProject;
7 |
8 | beforeAll(async () => {
9 | project = await prepareTestProject('install-force', manager);
10 | });
11 |
12 | test('nothing', async () => {
13 | await project.prepareClear({});
14 |
15 | await project.requestInstallForce(manager);
16 |
17 | const fastResponse = await project.requestGetFast();
18 | const fullResponse = await project.requestGetFull();
19 |
20 | expect(fastResponse.body).toEqual([]);
21 | expect(fullResponse.body).toEqual([]);
22 | });
23 |
24 | test('uninstalled', async () => {
25 | await project.prepareClear({
26 | dependencies: { 'npm-gui-tests': '^1.0.0' },
27 | });
28 |
29 | await project.requestInstallForce(manager);
30 |
31 | const fastResponse = await project.requestGetFast();
32 | const fullResponse = await project.requestGetFull();
33 |
34 | expect(fastResponse.body).toEqual([TEST[manager].PKG_A]);
35 | expect(fullResponse.body).toEqual([TEST[manager].PKG_A_INSTALLED]);
36 | });
37 |
38 | test('uninstalled', async () => {
39 | await project.prepareClear({
40 | dependencies: { 'npm-gui-tests': '^1.0.0' },
41 | install: true,
42 | });
43 |
44 | await project.requestInstallForce(manager);
45 |
46 | const fastResponse = await project.requestGetFast();
47 | const fullResponse = await project.requestGetFull();
48 |
49 | expect(fastResponse.body).toEqual([TEST[manager].PKG_A]);
50 | expect(fullResponse.body).toEqual([TEST[manager].PKG_A_INSTALLED]);
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/tests/install.test.ts:
--------------------------------------------------------------------------------
1 | import type { TestProject } from './tests-utils';
2 | import { managers, prepareTestProject, TEST } from './tests-utils';
3 |
4 | describe.each(managers)('%s install', (manager) => {
5 | // eslint-disable-next-line @typescript-eslint/init-declarations
6 | let project: TestProject;
7 |
8 | beforeAll(async () => {
9 | project = await prepareTestProject('install', manager);
10 | });
11 |
12 | test('nothing', async () => {
13 | await project.prepareClear({});
14 |
15 | await project.requestInstall();
16 |
17 | const fastResponse = await project.requestGetFast();
18 | const fullResponse = await project.requestGetFull();
19 |
20 | expect(fastResponse.body).toEqual([]);
21 | expect(fullResponse.body).toEqual([]);
22 | });
23 |
24 | test('uninstalled', async () => {
25 | await project.prepareClear({
26 | dependencies: { 'npm-gui-tests': '^1.0.0' },
27 | });
28 |
29 | await project.requestInstall();
30 |
31 | const fastResponse = await project.requestGetFast();
32 | const fullResponse = await project.requestGetFull();
33 |
34 | expect(fastResponse.body).toEqual([TEST[manager].PKG_A]);
35 | expect(fullResponse.body).toEqual([TEST[manager].PKG_A_INSTALLED]);
36 | });
37 |
38 | test('uninstalled', async () => {
39 | await project.prepareClear({
40 | dependencies: { 'npm-gui-tests': '^1.0.0' },
41 | install: true,
42 | });
43 |
44 | await project.requestInstall();
45 |
46 | const fastResponse = await project.requestGetFast();
47 | const fullResponse = await project.requestGetFull();
48 |
49 | expect(fastResponse.body).toEqual([TEST[manager].PKG_A]);
50 | expect(fullResponse.body).toEqual([TEST[manager].PKG_A_INSTALLED]);
51 | });
52 | });
53 |
--------------------------------------------------------------------------------
/tests/invalid-project.test.ts:
--------------------------------------------------------------------------------
1 | import { ensureDir } from 'fs-extra';
2 | import path from 'path';
3 | import api from 'supertest';
4 |
5 | import { app } from '../server';
6 | import { HTTP_STATUS_BAD_REQUEST } from '../server/utils/utils';
7 | import { encodePath } from './tests-utils';
8 |
9 | describe(`Invalid project for npm `, () => {
10 | test('should throw error', async () => {
11 | const testDirectoryPath = path.join(__dirname, 'test-project', 'invalid');
12 |
13 | await ensureDir(testDirectoryPath);
14 | const encodedTestDirectoryPath = encodePath(testDirectoryPath);
15 |
16 | const response = await api(app.server).get(
17 | `/api/project/${encodedTestDirectoryPath}/dependencies/install`,
18 | );
19 |
20 | expect(response.status).toBe(HTTP_STATUS_BAD_REQUEST);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/tests/managers.test.ts:
--------------------------------------------------------------------------------
1 | import api from 'supertest';
2 |
3 | import { app } from '../server';
4 | import { HTTP_STATUS_OK } from '../server/utils/utils';
5 |
6 | describe(`Package Managers`, () => {
7 | test('should return available package managers', async () => {
8 | const response = await api(app.server).get('/api/available-managers/');
9 | expect(response.status).toBe(HTTP_STATUS_OK);
10 |
11 | expect(response.body).toEqual({
12 | npm: true,
13 | pnpm: true,
14 | yarn: true,
15 | });
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/tests/search.test.ts:
--------------------------------------------------------------------------------
1 | import api from 'supertest';
2 |
3 | import { app } from '../server';
4 | import { HTTP_STATUS_OK } from '../server/utils/utils';
5 |
6 | describe(`Package Managers`, () => {
7 | test('should return available package managers', async () => {
8 | const response = await api(app.server)
9 | .post('/api/search/npm')
10 | .send({ query: 'npm-gui-tests' });
11 |
12 | expect(response.status).toBe(HTTP_STATUS_OK);
13 |
14 | expect(response.body).toPartiallyContain({
15 | name: 'npm-gui-tests',
16 | version: '2.1.1',
17 | repository: 'https://github.com/q-nick/npm-gui-tests',
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/tests/setup-tests.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line no-undef
2 | jest.setTimeout(60000);
3 |
--------------------------------------------------------------------------------
/tests/test-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "npm-gui-test-project",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "UNLICENSED"
11 | }
12 |
--------------------------------------------------------------------------------
/tests/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-turbocharge/node/tsconfig.json",
3 | "compilerOptions": {
4 | "target": "es2015",
5 | "lib": ["es2015"],
6 | "noEmit": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/units.test.ts:
--------------------------------------------------------------------------------
1 | import { executeCommand } from '../server/actions/execute-command';
2 | import {
3 | getDependenciesFromPackageJson,
4 | getDevelopmentDependenciesFromPackageJson,
5 | getRequiredFromPackageJson,
6 | getTypeFromPackageJson,
7 | } from '../server/utils/get-project-package-json';
8 |
9 | describe(`get package.json exceptions`, () => {
10 | test('getDependenciesFromPackageJson', () => {
11 | expect(getDependenciesFromPackageJson('anything')).toEqual({});
12 | });
13 |
14 | test('getDevDependenciesFromPackageJson', () => {
15 | expect(getDevelopmentDependenciesFromPackageJson('anything')).toEqual({});
16 | });
17 |
18 | test('getTypeFromPackageJson', () => {
19 | expect(getTypeFromPackageJson('anything', 'anything')).toBe('extraneous');
20 |
21 | expect(getTypeFromPackageJson('./', 'anything')).toBe('extraneous');
22 | });
23 |
24 | test('getRequiredFromPackageJson', () => {
25 | expect(getRequiredFromPackageJson('anything', 'anything')).toBe(undefined);
26 |
27 | expect(getRequiredFromPackageJson('./', 'anything')).toBe(undefined);
28 | });
29 |
30 | describe(`execute command exceptions`, () => {
31 | test('empty string', async () => {
32 | await expect(executeCommand('', '')).rejects.toThrowError();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "eslint-config-turbocharge/node/tsconfig.json",
3 | "references": [
4 | { "path": "./server" },
5 | { "path": "./client" },
6 | { "path": "./tests" }
7 | ],
8 | "compilerOptions": {
9 | "outDir": "./dist"
10 | },
11 | "files": []
12 | }
13 |
--------------------------------------------------------------------------------