import { Logger } from '@bpinternal/log4bot' import yargs, { YargsConfig, YargsSchema } from '@bpinternal/yargs-extra' import * as consts from '../src/consts' import { requiredBotSecrets } from './tests/bot-secrets' import { createDeployBot } from './tests/create-deploy-bot' import { createDeployBotWithDependencies } from './tests/create-deploy-bot-with-dependencies' import { createDeployIntegration } from './tests/create-deploy-integration' import { devBot } from './tests/dev-bot' import { installAllInterfaces } from './tests/install-interfaces' import { addIntegration, addPlugin, addLocalIntegrationKeepsRelativePath, addDevIntegrationSkipsBpDependencies, addDevIntegrationPreservesExistingBpDependency, reinstallLocalIntegration, } from './tests/install-package' import { requiredIntegrationSecrets } from './tests/integration-secrets' import { enforceWorkspaceHandleIntegration, enforceWorkspaceHandlePlugin, prependWorkspaceHandleIntegration, prependWorkspaceHandlePlugin, } from './tests/manage-workspace-handle' import { removePackage } from './tests/remove-package' import { Test } from './typings' import { sleep, TmpDirectory } from './utils' const tests: Test[] = [ createDeployBot, createDeployBotWithDependencies, createDeployIntegration, devBot, requiredBotSecrets, requiredIntegrationSecrets, prependWorkspaceHandleIntegration, enforceWorkspaceHandleIntegration, prependWorkspaceHandlePlugin, enforceWorkspaceHandlePlugin, addIntegration, addPlugin, addLocalIntegrationKeepsRelativePath, addDevIntegrationSkipsBpDependencies, addDevIntegrationPreservesExistingBpDependency, reinstallLocalIntegration, installAllInterfaces, removePackage, ] const timeout = (ms: number) => sleep(ms).then(() => { throw new Error(`Timeout after ${ms}ms`) }) const TIMEOUT = 300_000 const configSchema = { timeout: { type: 'number', default: TIMEOUT, }, verbose: { type: 'boolean', default: false, alias: 'v', }, filter: { type: 'string', }, workspaceId: { type: 'string', demandOption: true, }, workspaceHandle: { type: 'string', demandOption: true, }, token: { type: 'string', demandOption: true, }, apiUrl: { type: 'string', default: consts.defaultBotpressApiUrl, }, tunnelUrl: { type: 'string', default: consts.defaultTunnelUrl, }, sdkPath: { type: 'string', description: 'Path to the Botpress SDK to install; Allows using a version not released on NPM yet.', }, clientPath: { type: 'string', description: 'Path to the Botpress Client to install; Allows using a version not released on NPM yet.', }, } satisfies YargsSchema const main = async (argv: YargsConfig): Promise => { const logger = new Logger('e2e', { level: argv.verbose ? 'debug' : 'info' }) const filterRegex = argv.filter ? new RegExp(argv.filter) : null const filteredTests = tests.filter(({ name }) => (filterRegex ? filterRegex.test(name) : true)) logger.info(`Running ${filteredTests.length} / ${tests.length} tests`) const dependencies = { '@botpress/sdk': argv.sdkPath, '@botpress/client': argv.clientPath } satisfies Record< string, string | undefined > for (const { name, handler } of filteredTests) { const logLine = `### Running test: "${name}" ###` const logPad = '#'.repeat(logLine.length) logger.info(logPad) logger.info(logLine) logger.info(logPad + '\n') const loggerNamespace = name.replace(/ /g, '_').replace(/[^a-zA-Z0-9_]/g, '') const tmpDir = TmpDirectory.create() try { const t0 = Date.now() await Promise.race([ handler({ tmpDir: tmpDir.path, dependencies, logger: logger.sub(loggerNamespace), ...argv }), timeout(argv.timeout), ]) const t1 = Date.now() logger.info(`SUCCESS: "${name}" (${t1 - t0}ms)`) } catch (thrown) { const err = thrown instanceof Error ? thrown : new Error(`${thrown}`) logger.attachError(err).error(`FAILURE: "${name}"`) process.exit(1) } finally { tmpDir.cleanup() } } logger.info('All tests passed') process.exit(0) } void yargs.command('$0', 'Run E2E Tests', configSchema, main).parse()