refactor: use text as default field type to avoid breaking when future field types are added
This commit is contained in:
parent
f35bdb7611
commit
d3bd0b0cf9
4 changed files with 56 additions and 14 deletions
|
@ -1,8 +1,9 @@
|
|||
import fs from 'fs-extra';
|
||||
import { fromAny } from '@total-typescript/shoehorn';
|
||||
import { App, PrismaClient } from '@prisma/client';
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { setConfig } from '../../core/TipiConfig';
|
||||
import { AppInfo, checkAppRequirements, checkEnvFile, ensureAppFolder, generateEnvFile, getAppInfo, getAvailableApps, getEnvMap, getUpdateInfo } from './apps.helpers';
|
||||
import { AppInfo, appInfoSchema, checkAppRequirements, checkEnvFile, ensureAppFolder, generateEnvFile, getAppInfo, getAvailableApps, getEnvMap, getUpdateInfo } from './apps.helpers';
|
||||
import { createApp, createAppConfig } from '../../tests/apps.factory';
|
||||
import { Logger } from '../../core/Logger';
|
||||
import { getTestDbClient } from '../../../../tests/server/db-connection';
|
||||
|
@ -136,6 +137,41 @@ describe('Test: checkEnvFile', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('Test: appInfoSchema', () => {
|
||||
it('should default form_field type to text if it is wrong', async () => {
|
||||
// arrange
|
||||
const config = createAppConfig(fromAny({ form_fields: [{ env_variable: 'test', type: 'wrong', label: 'yo', required: true }] }));
|
||||
fs.writeFileSync(`/app/storage/app-data/${config.id}/config.json`, JSON.stringify(config));
|
||||
|
||||
// act
|
||||
const appInfo = appInfoSchema.safeParse(config);
|
||||
|
||||
// assert
|
||||
expect(appInfo.success).toBe(true);
|
||||
if (appInfo.success) {
|
||||
expect(appInfo.data.form_fields[0]?.type).toBe('text');
|
||||
} else {
|
||||
expect(true).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it('should default categories to ["utilities"] if it is wrong', async () => {
|
||||
// arrange
|
||||
const config = createAppConfig(fromAny({ categories: 'wrong' }));
|
||||
fs.writeFileSync(`/app/storage/app-data/${config.id}/config.json`, JSON.stringify(config));
|
||||
|
||||
// act
|
||||
const appInfo = appInfoSchema.safeParse(config);
|
||||
|
||||
// assert
|
||||
expect(appInfo.success).toBe(true);
|
||||
if (appInfo.success) {
|
||||
expect(appInfo.data.categories).toStrictEqual(['utilities']);
|
||||
} else {
|
||||
expect(true).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe('Test: generateEnvFile', () => {
|
||||
let app1: AppInfo;
|
||||
let appEntity1: App;
|
||||
|
|
|
@ -10,13 +10,17 @@ import { notEmpty } from '../../common/typescript.helpers';
|
|||
import { ARCHITECTURES } from '../../core/TipiConfig/TipiConfig';
|
||||
|
||||
const formFieldSchema = z.object({
|
||||
type: z.nativeEnum(FIELD_TYPES),
|
||||
type: z.nativeEnum(FIELD_TYPES).catch(() => FIELD_TYPES.TEXT),
|
||||
label: z.string(),
|
||||
placeholder: z.string().optional(),
|
||||
max: z.number().optional(),
|
||||
min: z.number().optional(),
|
||||
hint: z.string().optional(),
|
||||
options: z.object({ label: z.string(), value: z.string() }).array().optional(),
|
||||
required: z.boolean().optional().default(false),
|
||||
default: z.union([z.boolean(), z.string()]).optional(),
|
||||
regex: z.string().optional(),
|
||||
pattern_error: z.string().optional(),
|
||||
env_variable: z.string(),
|
||||
});
|
||||
|
||||
|
@ -32,7 +36,13 @@ export const appInfoSchema = z.object({
|
|||
author: z.string(),
|
||||
source: z.string(),
|
||||
website: z.string().optional(),
|
||||
categories: z.nativeEnum(APP_CATEGORIES).array(),
|
||||
categories: z
|
||||
.nativeEnum(APP_CATEGORIES)
|
||||
.array()
|
||||
.catch((ctx) => {
|
||||
Logger.warn(`Invalid categories "${JSON.stringify(ctx.input)}" defaulting to utilities`);
|
||||
return [APP_CATEGORIES.UTILITIES];
|
||||
}),
|
||||
url_suffix: z.string().optional(),
|
||||
form_fields: z.array(formFieldSchema).optional().default([]),
|
||||
https: z.boolean().optional().default(false),
|
||||
|
|
|
@ -2,7 +2,7 @@ import { faker } from '@faker-js/faker';
|
|||
import { App, PrismaClient } from '@prisma/client';
|
||||
import { Architecture } from '../core/TipiConfig/TipiConfig';
|
||||
import { AppInfo, appInfoSchema } from '../services/apps/apps.helpers';
|
||||
import { AppCategory, APP_CATEGORIES } from '../services/apps/apps.types';
|
||||
import { APP_CATEGORIES } from '../services/apps/apps.types';
|
||||
|
||||
interface IProps {
|
||||
installed?: boolean;
|
||||
|
@ -15,24 +15,19 @@ interface IProps {
|
|||
supportedArchitectures?: Architecture[];
|
||||
}
|
||||
|
||||
type CreateConfigParams = {
|
||||
id?: string;
|
||||
name?: string;
|
||||
categories?: AppCategory[];
|
||||
};
|
||||
|
||||
const createAppConfig = (props?: CreateConfigParams) =>
|
||||
const createAppConfig = (props?: Partial<AppInfo>) =>
|
||||
appInfoSchema.parse({
|
||||
id: props?.id || faker.random.alphaNumeric(32),
|
||||
id: faker.random.alphaNumeric(32),
|
||||
available: true,
|
||||
port: faker.datatype.number({ min: 30, max: 65535 }),
|
||||
name: props?.name || faker.random.alphaNumeric(32),
|
||||
name: faker.random.alphaNumeric(32),
|
||||
description: faker.random.alphaNumeric(32),
|
||||
tipi_version: 1,
|
||||
short_desc: faker.random.alphaNumeric(32),
|
||||
author: faker.random.alphaNumeric(32),
|
||||
source: faker.internet.url(),
|
||||
categories: props?.categories || [APP_CATEGORIES.AUTOMATION],
|
||||
categories: [APP_CATEGORIES.AUTOMATION],
|
||||
...props,
|
||||
});
|
||||
|
||||
const createApp = async (props: IProps, db?: PrismaClient) => {
|
||||
|
|
|
@ -8,6 +8,7 @@ jest.mock('../../src/server/core/Logger', () => ({
|
|||
Logger: {
|
||||
info: jest.fn(),
|
||||
error: jest.fn(),
|
||||
warn: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
Loading…
Reference in a new issue