Sync built files (#17379)
as title, upload built files to local storage --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
+4
-4
@@ -1,11 +1,11 @@
|
||||
import { runAppBuild } from '@/cli/__tests__/integration/utils/run-app-build.util';
|
||||
import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util';
|
||||
import { join } from 'path';
|
||||
|
||||
import { runAppBuild } from '@/cli/__tests__/integration/utils/run-app-build.util';
|
||||
import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util';
|
||||
import { defineConsoleOutputTests } from './tests/console-output.tests';
|
||||
import { defineManifestTests } from '../app-dev/tests/manifest.tests';
|
||||
import { defineFrontComponentsTests } from '../app-dev/tests/front-components.tests';
|
||||
import { defineFunctionsTests } from '../app-dev/tests/functions.tests';
|
||||
import { defineManifestTests } from '../app-dev/tests/manifest.tests';
|
||||
import { defineConsoleOutputTests } from './tests/console-output.tests';
|
||||
|
||||
const APP_PATH = join(__dirname, '../..');
|
||||
|
||||
|
||||
+4
-1
@@ -33,7 +33,10 @@ export const defineConsoleOutputTests = (
|
||||
});
|
||||
|
||||
it('should contain front-components-watch messages', () => {
|
||||
const output = getOutputByPrefix(getResult().output, 'front-components-watch');
|
||||
const output = getOutputByPrefix(
|
||||
getResult().output,
|
||||
'front-components-watch',
|
||||
);
|
||||
|
||||
expect(output).toContain('[front-components-watch] 🎨 Building...');
|
||||
expect(output).toContain('[front-components-watch] ✓ Built');
|
||||
|
||||
+3
-3
@@ -3,9 +3,9 @@ import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-
|
||||
import { join } from 'path';
|
||||
|
||||
import { defineConsoleOutputTests } from './tests/console-output.tests';
|
||||
import { defineFrontComponentsTests } from './tests/front-components.tests';
|
||||
import { defineFunctionsTests } from './tests/functions.tests';
|
||||
import { defineManifestTests } from './tests/manifest.tests';
|
||||
import { defineManifestTests } from '../app-dev/tests/manifest.tests';
|
||||
import { defineFrontComponentsTests } from '../app-dev/tests/front-components.tests';
|
||||
import { defineFunctionsTests } from '../app-dev/tests/functions.tests';
|
||||
|
||||
const APP_PATH = join(__dirname, '../..');
|
||||
|
||||
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
import { FieldType } from '@/application';
|
||||
import type { ApplicationManifest } from 'twenty-shared/application';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
|
||||
export const EXPECTED_MANIFEST: ApplicationManifest = {
|
||||
sources: {},
|
||||
application: {
|
||||
applicationVariables: {
|
||||
DEFAULT_RECIPIENT_NAME: {
|
||||
description: 'Default recipient name for postcards',
|
||||
isSecret: false,
|
||||
universalIdentifier: '19e94e59-d4fe-4251-8981-b96d0a9f74de',
|
||||
value: 'Alex Karp',
|
||||
},
|
||||
},
|
||||
description: 'A simple hello world app',
|
||||
displayName: 'Hello World',
|
||||
functionRoleUniversalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
|
||||
icon: 'IconWorld',
|
||||
universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7',
|
||||
},
|
||||
frontComponents: [
|
||||
{
|
||||
builtComponentPath: 'front-components/src/root.front-component.mjs',
|
||||
builtComponentChecksum: '[checksum]',
|
||||
componentName: 'RootComponent',
|
||||
description: 'A root-level front component',
|
||||
name: 'root-component',
|
||||
sourceComponentPath: 'src/root.front-component.tsx',
|
||||
universalIdentifier: 'a0a1a2a3-a4a5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
builtComponentPath:
|
||||
'front-components/src/components/card.front-component.mjs',
|
||||
builtComponentChecksum: '[checksum]',
|
||||
componentName: 'CardDisplay',
|
||||
description: 'A component using an external component file',
|
||||
name: 'card-component',
|
||||
sourceComponentPath: 'src/components/card.front-component.tsx',
|
||||
universalIdentifier: 'i0i1i2i3-i4i5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
builtComponentPath:
|
||||
'front-components/src/components/greeting.front-component.mjs',
|
||||
builtComponentChecksum: '[checksum]',
|
||||
componentName: 'GreetingComponent',
|
||||
description: 'A component that uses greeting utility',
|
||||
name: 'greeting-component',
|
||||
sourceComponentPath: 'src/components/greeting.front-component.tsx',
|
||||
universalIdentifier: 'h0h1h2h3-h4h5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
builtComponentPath:
|
||||
'front-components/src/components/test.front-component.mjs',
|
||||
builtComponentChecksum: '[checksum]',
|
||||
componentName: 'TestComponent',
|
||||
description: 'A test front component',
|
||||
name: 'test-component',
|
||||
sourceComponentPath: 'src/components/test.front-component.tsx',
|
||||
universalIdentifier: 'f1234567-abcd-4000-8000-000000000001',
|
||||
},
|
||||
],
|
||||
objectExtensions: [
|
||||
{
|
||||
fields: [
|
||||
{
|
||||
description: 'Priority level for the post card (1-10)',
|
||||
label: 'Priority',
|
||||
name: 'priority',
|
||||
type: FieldType.NUMBER,
|
||||
universalIdentifier: '7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d',
|
||||
},
|
||||
{
|
||||
description: 'Post card category',
|
||||
label: 'Category',
|
||||
name: 'category',
|
||||
options: [
|
||||
{
|
||||
color: 'blue',
|
||||
label: 'Personal',
|
||||
position: 0,
|
||||
value: 'PERSONAL',
|
||||
},
|
||||
{
|
||||
color: 'green',
|
||||
label: 'Business',
|
||||
position: 1,
|
||||
value: 'BUSINESS',
|
||||
},
|
||||
{
|
||||
color: 'orange',
|
||||
label: 'Promotional',
|
||||
position: 2,
|
||||
value: 'PROMOTIONAL',
|
||||
},
|
||||
],
|
||||
type: FieldType.SELECT,
|
||||
universalIdentifier: '8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e',
|
||||
},
|
||||
],
|
||||
targetObject: {
|
||||
nameSingular: 'postCard',
|
||||
},
|
||||
},
|
||||
],
|
||||
objects: [
|
||||
{
|
||||
description: 'A simple root-level object',
|
||||
fields: [
|
||||
{
|
||||
label: 'Title',
|
||||
name: 'title',
|
||||
type: FieldType.TEXT,
|
||||
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000002',
|
||||
},
|
||||
{
|
||||
label: 'Body',
|
||||
name: 'body',
|
||||
type: FieldType.TEXT,
|
||||
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000003',
|
||||
},
|
||||
],
|
||||
icon: 'IconNote',
|
||||
labelPlural: 'Root notes',
|
||||
labelSingular: 'Root note',
|
||||
namePlural: 'rootNotes',
|
||||
nameSingular: 'rootNote',
|
||||
universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
description: 'A post card object',
|
||||
fields: [
|
||||
{
|
||||
description: "Postcard's content",
|
||||
icon: 'IconAbc',
|
||||
label: 'Content',
|
||||
name: 'content',
|
||||
type: FieldType.TEXT,
|
||||
universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
|
||||
},
|
||||
{
|
||||
icon: 'IconUser',
|
||||
label: 'Recipient name',
|
||||
name: 'recipientName',
|
||||
type: FieldType.FULL_NAME,
|
||||
universalIdentifier: 'c6aa31f3-da76-4ac6-889f-475e226009ac',
|
||||
},
|
||||
{
|
||||
icon: 'IconHome',
|
||||
label: 'Recipient address',
|
||||
name: 'recipientAddress',
|
||||
type: FieldType.ADDRESS,
|
||||
universalIdentifier: '95045777-a0ad-49ec-98f9-22f9fc0c8266',
|
||||
},
|
||||
{
|
||||
defaultValue: "'DRAFT'",
|
||||
icon: 'IconSend',
|
||||
label: 'Status',
|
||||
name: 'status',
|
||||
options: [
|
||||
{
|
||||
color: 'gray',
|
||||
label: 'Draft',
|
||||
position: 0,
|
||||
value: 'DRAFT',
|
||||
},
|
||||
{
|
||||
color: 'orange',
|
||||
label: 'Sent',
|
||||
position: 1,
|
||||
value: 'SENT',
|
||||
},
|
||||
{
|
||||
color: 'green',
|
||||
label: 'Delivered',
|
||||
position: 2,
|
||||
value: 'DELIVERED',
|
||||
},
|
||||
{
|
||||
color: 'orange',
|
||||
label: 'Returned',
|
||||
position: 3,
|
||||
value: 'RETURNED',
|
||||
},
|
||||
],
|
||||
type: FieldType.SELECT,
|
||||
universalIdentifier: '87b675b8-dd8c-4448-b4ca-20e5a2234a1e',
|
||||
},
|
||||
{
|
||||
defaultValue: null,
|
||||
icon: 'IconCheck',
|
||||
isNullable: true,
|
||||
label: 'Delivered at',
|
||||
name: 'deliveredAt',
|
||||
type: FieldType.DATE_TIME,
|
||||
universalIdentifier: 'e06abe72-5b44-4e7f-93be-afc185a3c433',
|
||||
},
|
||||
],
|
||||
icon: 'IconMail',
|
||||
labelPlural: 'Post cards',
|
||||
labelSingular: 'Post card',
|
||||
namePlural: 'postCards',
|
||||
nameSingular: 'postCard',
|
||||
universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
|
||||
},
|
||||
],
|
||||
packageJson: {
|
||||
name: 'rich-app',
|
||||
version: '0.1.0',
|
||||
license: 'MIT',
|
||||
engines: {
|
||||
node: '^24.5.0',
|
||||
npm: 'please-use-yarn',
|
||||
yarn: '>=4.0.2',
|
||||
},
|
||||
packageManager: 'yarn@4.9.2',
|
||||
scripts: {
|
||||
'auth:login': 'twenty auth:login',
|
||||
'auth:logout': 'twenty auth:logout',
|
||||
'auth:status': 'twenty auth:status',
|
||||
'auth:switch': 'twenty auth:switch',
|
||||
'auth:list': 'twenty auth:list',
|
||||
'app:dev': 'twenty app:dev',
|
||||
'app:build': 'twenty app:build',
|
||||
'app:sync': 'twenty app:sync',
|
||||
'entity:add': 'twenty entity:add',
|
||||
'app:generate': 'twenty app:generate',
|
||||
'function:logs': 'twenty function:logs',
|
||||
'function:execute': 'twenty function:execute',
|
||||
'app:uninstall': 'twenty app:uninstall',
|
||||
help: 'twenty help',
|
||||
lint: 'eslint',
|
||||
'lint:fix': 'eslint --fix',
|
||||
},
|
||||
dependencies: {
|
||||
'twenty-sdk': 'latest',
|
||||
},
|
||||
devDependencies: {
|
||||
typescript: '^5.9.3',
|
||||
'@types/node': '^24.7.2',
|
||||
'@types/react': '^19.0.2',
|
||||
react: '^19.0.2',
|
||||
eslint: '^9.32.0',
|
||||
'typescript-eslint': '^8.50.0',
|
||||
},
|
||||
},
|
||||
roles: [
|
||||
{
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToApiKeys: false,
|
||||
canBeAssignedToUsers: true,
|
||||
canDestroyAllObjectRecords: false,
|
||||
canReadAllObjectRecords: true,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canUpdateAllObjectRecords: false,
|
||||
canUpdateAllSettings: false,
|
||||
description: 'A simple root-level role',
|
||||
label: 'Root role',
|
||||
universalIdentifier: 'c0c1c2c3-c4c5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToApiKeys: false,
|
||||
canBeAssignedToUsers: false,
|
||||
canDestroyAllObjectRecords: false,
|
||||
canReadAllObjectRecords: false,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canUpdateAllObjectRecords: false,
|
||||
canUpdateAllSettings: false,
|
||||
description: 'Default role for function Twenty client',
|
||||
fieldPermissions: [
|
||||
{
|
||||
canReadFieldValue: false,
|
||||
canUpdateFieldValue: false,
|
||||
fieldName: 'content',
|
||||
objectNameSingular: 'postCard',
|
||||
},
|
||||
],
|
||||
label: 'Default function role',
|
||||
objectPermissions: [
|
||||
{
|
||||
canDestroyObjectRecords: false,
|
||||
canReadObjectRecords: true,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canUpdateObjectRecords: true,
|
||||
objectNameSingular: 'postCard',
|
||||
},
|
||||
],
|
||||
permissionFlags: [PermissionFlagType.APPLICATIONS],
|
||||
universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
|
||||
},
|
||||
],
|
||||
functions: [
|
||||
{
|
||||
builtHandlerChecksum: '[checksum]',
|
||||
builtHandlerPath: 'functions/src/root.function.mjs',
|
||||
handlerName: 'rootHandler',
|
||||
name: 'root-function',
|
||||
sourceHandlerPath: 'src/root.function.ts',
|
||||
timeoutSeconds: 5,
|
||||
triggers: [
|
||||
{
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: false,
|
||||
path: '/root',
|
||||
type: 'route',
|
||||
universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000002',
|
||||
},
|
||||
],
|
||||
universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
builtHandlerChecksum: '[checksum]',
|
||||
builtHandlerPath: 'functions/src/functions/greeting.function.mjs',
|
||||
handlerName: 'greetingHandler',
|
||||
name: 'greeting-function',
|
||||
sourceHandlerPath: 'src/functions/greeting.function.ts',
|
||||
timeoutSeconds: 5,
|
||||
triggers: [
|
||||
{
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: false,
|
||||
path: '/greet',
|
||||
type: 'route',
|
||||
universalIdentifier: 'g0g1g2g3-g4g5-4000-8000-000000000002',
|
||||
},
|
||||
],
|
||||
universalIdentifier: 'g0g1g2g3-g4g5-4000-8000-000000000001',
|
||||
},
|
||||
{
|
||||
builtHandlerChecksum: '[checksum]',
|
||||
builtHandlerPath: 'functions/src/functions/test-function-2.function.mjs',
|
||||
handlerName: 'testFunction2',
|
||||
name: 'test-function-2',
|
||||
sourceHandlerPath: 'src/utils/test-function-2.util.ts',
|
||||
timeoutSeconds: 2,
|
||||
triggers: [
|
||||
{
|
||||
pattern: '0 0 1 1 *',
|
||||
type: 'cron',
|
||||
universalIdentifier: '9fd0dda9-4664-4fbc-9656-509f4477b9ff',
|
||||
},
|
||||
],
|
||||
universalIdentifier: 'eb3ffc98-88ec-45d4-9b4a-56833b219ccb',
|
||||
},
|
||||
{
|
||||
builtHandlerChecksum: '[checksum]',
|
||||
builtHandlerPath: 'functions/src/functions/test-function.function.mjs',
|
||||
handlerName: 'handler',
|
||||
name: 'test-function',
|
||||
sourceHandlerPath: 'src/functions/test-function.function.ts',
|
||||
timeoutSeconds: 2,
|
||||
triggers: [
|
||||
{
|
||||
forwardedRequestHeaders: ['signature'],
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: false,
|
||||
path: '/post-card/create',
|
||||
type: 'route',
|
||||
universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6',
|
||||
},
|
||||
{
|
||||
pattern: '0 0 1 1 *',
|
||||
type: 'cron',
|
||||
universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2',
|
||||
},
|
||||
{
|
||||
eventName: 'person.created',
|
||||
type: 'databaseEvent',
|
||||
universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156',
|
||||
},
|
||||
],
|
||||
universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
|
||||
},
|
||||
],
|
||||
};
|
||||
+7
-2
@@ -8,7 +8,9 @@ export const defineConsoleOutputTests = (
|
||||
it('should contain init messages', () => {
|
||||
const output = getOutputByPrefix(getResult().output, 'init');
|
||||
|
||||
expect(output).toContain('[init] 🚀 Starting Twenty Application Development Mode');
|
||||
expect(output).toContain(
|
||||
'[init] 🚀 Starting Twenty Application Development Mode',
|
||||
);
|
||||
expect(output).toContain('[init] 📁 App Path:');
|
||||
});
|
||||
|
||||
@@ -33,7 +35,10 @@ export const defineConsoleOutputTests = (
|
||||
});
|
||||
|
||||
it('should contain front-components-watch messages', () => {
|
||||
const output = getOutputByPrefix(getResult().output, 'front-components-watch');
|
||||
const output = getOutputByPrefix(
|
||||
getResult().output,
|
||||
'front-components-watch',
|
||||
);
|
||||
|
||||
expect(output).toContain('[front-components-watch] 🎨 Building...');
|
||||
expect(output).toContain('[front-components-watch] ✓ Built');
|
||||
|
||||
+4
-1
@@ -4,7 +4,10 @@ import { join } from 'path';
|
||||
export const defineFrontComponentsTests = (appPath: string): void => {
|
||||
describe('front-components', () => {
|
||||
it('should have built front components preserving source path structure', async () => {
|
||||
const frontComponentsDir = join(appPath, '.twenty/output/front-components');
|
||||
const frontComponentsDir = join(
|
||||
appPath,
|
||||
'.twenty/output/front-components',
|
||||
);
|
||||
const files = await fs.readdir(frontComponentsDir, { recursive: true });
|
||||
const sortedFiles = files.map((f) => f.toString()).sort();
|
||||
|
||||
|
||||
+5
-3
@@ -2,7 +2,7 @@ import * as fs from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
|
||||
import { normalizeManifestForComparison } from '@/cli/__tests__/integration/utils/normalize-manifest.util';
|
||||
import expectedManifest from '../manifest.expected.json';
|
||||
import { EXPECTED_MANIFEST } from '../expected-manifest';
|
||||
|
||||
export const defineManifestTests = (appPath: string): void => {
|
||||
const manifestOutputPath = join(appPath, '.twenty/output/manifest.json');
|
||||
@@ -16,7 +16,7 @@ export const defineManifestTests = (appPath: string): void => {
|
||||
const { sources: _sources, ...sanitizedManifest } = manifest;
|
||||
|
||||
expect(normalizeManifestForComparison(sanitizedManifest)).toEqual(
|
||||
normalizeManifestForComparison(expectedManifest),
|
||||
normalizeManifestForComparison(EXPECTED_MANIFEST),
|
||||
);
|
||||
|
||||
for (const fn of manifest.functions) {
|
||||
@@ -36,7 +36,9 @@ export const defineManifestTests = (appPath: string): void => {
|
||||
const manifest = await fs.readJson(manifestOutputPath);
|
||||
|
||||
expect(manifest?.application.displayName).toBe('Hello World');
|
||||
expect(manifest?.application.description).toBe('A simple hello world app');
|
||||
expect(manifest?.application.description).toBe(
|
||||
'A simple hello world app',
|
||||
);
|
||||
});
|
||||
|
||||
it('should load all entity types', async () => {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { runAppBuild } from '../../../../integration/utils/run-app-build.util';
|
||||
import { type RunCliCommandResult } from '../../../../integration/utils/run-cli-command.util';
|
||||
import { runAppBuild } from '@/cli/__tests__/integration/utils/run-app-build.util';
|
||||
import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util';
|
||||
import { defineConsoleOutputTests } from './tests/console-output.tests';
|
||||
import { defineFrontComponentsTests } from '../app-dev/tests/front-components.tests';
|
||||
import { defineFunctionsTests } from '../app-dev/tests/functions.tests';
|
||||
|
||||
+4
-1
@@ -33,7 +33,10 @@ export const defineConsoleOutputTests = (
|
||||
});
|
||||
|
||||
it('should contain front-components-watch messages', () => {
|
||||
const output = getOutputByPrefix(getResult().output, 'front-components-watch');
|
||||
const output = getOutputByPrefix(
|
||||
getResult().output,
|
||||
'front-components-watch',
|
||||
);
|
||||
|
||||
expect(output).toContain('[front-components-watch] 🎨 Building...');
|
||||
expect(output).toContain('[front-components-watch] ✓ Built');
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { join } from 'path';
|
||||
|
||||
import { runAppDev } from '../../../../integration/utils/run-app-dev.util';
|
||||
import { type RunCliCommandResult } from '../../../../integration/utils/run-cli-command.util';
|
||||
import { runAppDev } from '@/cli/__tests__/integration/utils/run-app-dev.util';
|
||||
import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util';
|
||||
import { defineConsoleOutputTests } from './tests/console-output.tests';
|
||||
import { defineFrontComponentsTests } from './tests/front-components.tests';
|
||||
import { defineFunctionsTests } from './tests/functions.tests';
|
||||
|
||||
+7
-2
@@ -8,7 +8,9 @@ export const defineConsoleOutputTests = (
|
||||
it('should contain init messages', () => {
|
||||
const output = getOutputByPrefix(getResult().output, 'init');
|
||||
|
||||
expect(output).toContain('[init] 🚀 Starting Twenty Application Development Mode');
|
||||
expect(output).toContain(
|
||||
'[init] 🚀 Starting Twenty Application Development Mode',
|
||||
);
|
||||
expect(output).toContain('[init] 📁 App Path:');
|
||||
});
|
||||
|
||||
@@ -33,7 +35,10 @@ export const defineConsoleOutputTests = (
|
||||
});
|
||||
|
||||
it('should contain front-components-watch messages', () => {
|
||||
const output = getOutputByPrefix(getResult().output, 'front-components-watch');
|
||||
const output = getOutputByPrefix(
|
||||
getResult().output,
|
||||
'front-components-watch',
|
||||
);
|
||||
|
||||
expect(output).toContain('[front-components-watch] 🎨 Building...');
|
||||
expect(output).toContain('[front-components-watch] ✓ Built');
|
||||
|
||||
+4
-1
@@ -4,7 +4,10 @@ import { join } from 'path';
|
||||
export const defineFrontComponentsTests = (appPath: string): void => {
|
||||
describe('front-components', () => {
|
||||
it('should have built front components at root level', async () => {
|
||||
const frontComponentsDir = join(appPath, '.twenty/output/front-components');
|
||||
const frontComponentsDir = join(
|
||||
appPath,
|
||||
'.twenty/output/front-components',
|
||||
);
|
||||
const files = await fs.readdir(frontComponentsDir, { recursive: true });
|
||||
const sortedFiles = files.map((f) => f.toString()).sort();
|
||||
|
||||
|
||||
+1
-4
@@ -8,10 +8,7 @@ export const defineFunctionsTests = (appPath: string): void => {
|
||||
const files = await fs.readdir(functionsDir, { recursive: true });
|
||||
const sortedFiles = files.map((f) => f.toString()).sort();
|
||||
|
||||
expect(sortedFiles).toEqual([
|
||||
'my.function.mjs',
|
||||
'my.function.mjs.map',
|
||||
]);
|
||||
expect(sortedFiles).toEqual(['my.function.mjs', 'my.function.mjs.map']);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
+16
-5
@@ -16,14 +16,21 @@ export const defineManifestTests = (appPath: string): void => {
|
||||
it('should have correct manifest content', async () => {
|
||||
const manifestPath = join(appPath, '.twenty/output/manifest.json');
|
||||
const manifest: ApplicationManifest = await fs.readJSON(manifestPath);
|
||||
const expectedPath = join(appPath, '__integration__/app-dev/manifest.expected.json');
|
||||
const expectedPath = join(
|
||||
appPath,
|
||||
'__integration__/app-dev/manifest.expected.json',
|
||||
);
|
||||
const expected: ApplicationManifest = await fs.readJSON(expectedPath);
|
||||
|
||||
expect(manifest.application).toEqual(expected.application);
|
||||
expect(manifest.objects).toEqual(expected.objects);
|
||||
|
||||
expect(normalizeManifestForComparison({ functions: manifest.functions }).functions).toEqual(
|
||||
normalizeManifestForComparison({ functions: expected.functions }).functions,
|
||||
expect(
|
||||
normalizeManifestForComparison({ functions: manifest.functions })
|
||||
.functions,
|
||||
).toEqual(
|
||||
normalizeManifestForComparison({ functions: expected.functions })
|
||||
.functions,
|
||||
);
|
||||
|
||||
for (const fn of manifest.functions) {
|
||||
@@ -33,9 +40,13 @@ export const defineManifestTests = (appPath: string): void => {
|
||||
}
|
||||
|
||||
expect(
|
||||
normalizeManifestForComparison({ frontComponents: manifest.frontComponents }).frontComponents,
|
||||
normalizeManifestForComparison({
|
||||
frontComponents: manifest.frontComponents,
|
||||
}).frontComponents,
|
||||
).toEqual(
|
||||
normalizeManifestForComparison({ frontComponents: expected.frontComponents }).frontComponents,
|
||||
normalizeManifestForComparison({
|
||||
frontComponents: expected.frontComponents,
|
||||
}).frontComponents,
|
||||
);
|
||||
|
||||
for (const component of manifest.frontComponents ?? []) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type TwentyConfig } from '@/cli/utilities/config/services/config.service';
|
||||
import { type TwentyConfig } from '@/cli/utilities/config/config-service';
|
||||
|
||||
export const testConfig: TwentyConfig = {
|
||||
apiUrl: 'http://localhost:3000',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ConfigService } from '@/cli/utilities/config/services/config.service';
|
||||
import { ConfigService } from '@/cli/utilities/config/config-service';
|
||||
import { testConfig } from '@/cli/__tests__/e2e/constants/testConfig';
|
||||
import { vi, beforeAll, afterAll } from 'vitest';
|
||||
|
||||
|
||||
+9
-2
@@ -1,6 +1,13 @@
|
||||
export type LogPrefix = 'init' | 'manifest-watch' | 'functions-watch' | 'front-components-watch';
|
||||
export type LogPrefix =
|
||||
| 'init'
|
||||
| 'manifest-watch'
|
||||
| 'functions-watch'
|
||||
| 'front-components-watch';
|
||||
|
||||
export const getOutputByPrefix = (output: string, prefix: LogPrefix): string => {
|
||||
export const getOutputByPrefix = (
|
||||
output: string,
|
||||
prefix: LogPrefix,
|
||||
): string => {
|
||||
const prefixPattern = `[${prefix}]`;
|
||||
const lines = output.split('\n');
|
||||
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
// Loose type for JSON manifest imports where enum values are inferred as strings
|
||||
type JsonManifestInput = {
|
||||
functions?: Array<{ builtHandlerChecksum?: string | null; [key: string]: unknown }>;
|
||||
frontComponents?: Array<{ builtComponentChecksum?: string | null; [key: string]: unknown }>;
|
||||
functions?: Array<{
|
||||
builtHandlerChecksum?: string | null;
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
frontComponents?: Array<{
|
||||
builtComponentChecksum?: string | null;
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
|
||||
@@ -20,4 +26,5 @@ export const normalizeManifestForComparison = <T extends JsonManifestInput>(
|
||||
? '[checksum]'
|
||||
: null,
|
||||
})),
|
||||
sources: {}, // removing sources for now, waiting compressed file implementation
|
||||
});
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { runCliCommand, type RunCliCommandResult } from './run-cli-command.util';
|
||||
import {
|
||||
runCliCommand,
|
||||
type RunCliCommandResult,
|
||||
} from './run-cli-command.util';
|
||||
|
||||
export type RunAppBuildOptions = {
|
||||
appPath: string;
|
||||
timeout?: number;
|
||||
};
|
||||
|
||||
export const runAppBuild = (options: RunAppBuildOptions): Promise<RunCliCommandResult> => {
|
||||
export const runAppBuild = (
|
||||
options: RunAppBuildOptions,
|
||||
): Promise<RunCliCommandResult> => {
|
||||
const { appPath, timeout = 30000 } = options;
|
||||
|
||||
// app:build runs once and exits, so we don't wait for specific output
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { runCliCommand, type RunCliCommandResult } from './run-cli-command.util';
|
||||
import {
|
||||
runCliCommand,
|
||||
type RunCliCommandResult,
|
||||
} from './run-cli-command.util';
|
||||
|
||||
export type RunAppDevOptions = {
|
||||
appPath: string;
|
||||
timeout?: number;
|
||||
};
|
||||
|
||||
export const runAppDev = (options: RunAppDevOptions): Promise<RunCliCommandResult> => {
|
||||
export const runAppDev = (
|
||||
options: RunAppDevOptions,
|
||||
): Promise<RunCliCommandResult> => {
|
||||
const { appPath, timeout = 30000 } = options;
|
||||
|
||||
|
||||
return runCliCommand({
|
||||
command: 'app:dev',
|
||||
args: [appPath],
|
||||
|
||||
@@ -23,12 +23,7 @@ export type RunCliCommandResult = {
|
||||
export const runCliCommand = (
|
||||
options: RunCliCommandOptions,
|
||||
): Promise<RunCliCommandResult> => {
|
||||
const {
|
||||
command,
|
||||
args = [],
|
||||
waitForOutput,
|
||||
timeout = 30000,
|
||||
} = options;
|
||||
const { command, args = [], waitForOutput, timeout = 30000 } = options;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
// Run from CLI directory to use twenty-sdk's tsconfig paths
|
||||
@@ -68,7 +63,7 @@ export const runCliCommand = (
|
||||
setTimeout(() => {
|
||||
child.kill();
|
||||
resolve({ success: true, output });
|
||||
}, 500);
|
||||
}, 1500);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
export const sanitizeOutput = (output: string): string => {
|
||||
return output
|
||||
// Remove ANSI color codes
|
||||
.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '')
|
||||
// Normalize file paths (replace any absolute path to a test app)
|
||||
.replace(/\/[^\s]+\/__tests__\/apps\/[^/]+/g, '<APP_PATH>')
|
||||
// Normalize timestamps
|
||||
.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/g, '<TIMESTAMP>')
|
||||
// Normalize durations
|
||||
.replace(/\d+ms/g, '<DURATION>')
|
||||
// Trim trailing whitespace from each line
|
||||
.split('\n')
|
||||
.map((line) => line.trimEnd())
|
||||
.join('\n')
|
||||
.trim();
|
||||
return (
|
||||
output
|
||||
// Remove ANSI color codes
|
||||
.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '')
|
||||
// Normalize file paths (replace any absolute path to a test app)
|
||||
.replace(/\/[^\s]+\/__tests__\/apps\/[^/]+/g, '<APP_PATH>')
|
||||
// Normalize timestamps
|
||||
.replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/g, '<TIMESTAMP>')
|
||||
// Normalize durations
|
||||
.replace(/\d+ms/g, '<DURATION>')
|
||||
// Trim trailing whitespace from each line
|
||||
.split('\n')
|
||||
.map((line) => line.trimEnd())
|
||||
.join('\n')
|
||||
.trim()
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user