Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
350 changes: 350 additions & 0 deletions packages/create-robo/__tests__/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,350 @@
import { promises as fs } from 'fs'
import path from 'node:path'
import { SpawnOptions, spawn } from 'node:child_process'
const FOLDER_PROJECTS_TEST_PATH = path.join(process.cwd(), '__tests__', 'projects')
const LOCAL_COPY_OF_ROBO_CREATE_PATH = path.join('..', '..', 'dist', 'index.js')
// Do not forget to install all required package managers !

// KNOWS ISSUES

// None of the package manager specific tests are passing.

/**
* Plain Javascript: JavaScript, zero features, and credentials.
Plain TypeScript: TypeScript, zero features, and credentials.
Standard JavaScript: JavaScript, recommended features, and credentials.
Standard TypeScript: TypeScript, recommended features, and credentials.

Skipped Credentials JS: JavaScript, recommended features, and skip credentials.
Skipped Credentials TS: TypeScript, recommended features, and skip credentials.

Standard JS Plugin: Same as Standard JS but as a plugin.
Standard TS Plugin: Same as Standard TS but as a plugin.
*/

async function areCredentialsSet(project_path: string): Promise<boolean> {
const envCreds = await fs.readFile(project_path)
const isCredentialsSet = envCreds.includes(`Credentials`)
return isCredentialsSet
}

async function areFeaturesInstalled(features: string[], project_name: string): Promise<boolean> {
const featuresInstalled: boolean[] = []

for (const feature of features) {
const feature_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, feature)
await fs
.access(feature_path)
.then(() => featuresInstalled.push(true))
.catch(() => false)
}

return featuresInstalled.filter((plugin) => plugin !== true).length <= 0 ? true : false
}

async function arePluginsInstalled(plugins: string[], project_name: string): Promise<boolean> {
const pluginsInstalled: boolean[] = []

for (const plugin of plugins) {
const plugin_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'config', 'plugins', `${plugin}.mjs`)
await fs
.access(plugin_path)
.then(() => pluginsInstalled.push(true))
.catch(() => false)
}

return pluginsInstalled.filter((plugin) => plugin !== true).length <= 0 ? true : false
}

describe('Create Robos ', () => {
beforeAll(async () => {
await fs.rmdir(FOLDER_PROJECTS_TEST_PATH, { recursive: true })
await fs.mkdir(FOLDER_PROJECTS_TEST_PATH)
}, 15000)

// Common

it('Plain Javascript: JavaScript, zero features, and credentials.', async () => {
const project_name = `JZFC`
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -js -f '' `, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)
const isCredentialsSet = await areCredentialsSet(env_file_path)
expect(isCredentialsSet).toBeTruthy()
}, 20000)

it('Pain Typescript: TypeScript, zero features, and credentials.', async () => {
const project_name = `TZFC`
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -f '' `, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)
const isCredentialsSet = await areCredentialsSet(env_file_path)
expect(isCredentialsSet).toBeTruthy()
}, 20000)

it(`Standard JavaScript: JavaScript, recommended features, and credentials.`, async () => {
const project_name = `JRFC`
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -js -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)
const isCredentialsSet = await areCredentialsSet(env_file_path)
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (featureInstalled) {
expect(isCredentialsSet).toBeTruthy()
}
}, 20000)

it(`Standard TypeScript: TypeScript, recommended features, and credentials.`, async () => {
const project_name = `TRFC`
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)

const isCredentialsSet = await areCredentialsSet(env_file_path)
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (featureInstalled) {
expect(isCredentialsSet).toBeTruthy()
}
}, 20000)

it(`Skipped Credentials JS: JavaScript, recommended features, skip credentials.`, async () => {
const project_name = `JRFSC`
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -js -f prettier,eslint`, false, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)

const isCredentialsSet = await areCredentialsSet(env_file_path)
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (featureInstalled) {
expect(isCredentialsSet).toBeFalsy()
}
}, 20000)

it(`Skipped Credentials TS: TypeScript, recommended features, skip credentials.`, async () => {
const project_name = `TRFSC`
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -f prettier,eslint`, false, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)

const isCredentialsSet = await areCredentialsSet(env_file_path)
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (featureInstalled) {
expect(isCredentialsSet).toBeFalsy()
}
}, 20000)

it(`Standard JS Plugin: Same as Standard JS but as a plugin.`, async () => {
const project_name = 'JSTANDARP'
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -js --plugin -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const md_file_path = fs
.access(path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'DEVELOPMENT.md'))
.then(() => true)
.catch(() => false)
const isPlugin = (
await fs.readFile(path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'config', 'robo.mjs'))
).includes("type: 'plugin'")
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (md_file_path && featureInstalled) {
expect(isPlugin).toBeTruthy()
}
}, 20000)

it(`Standard TS Plugin: Same as Standard TS but as a plugin.`, async () => {
const project_name = 'TSTANDARDP'
await exec(
`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -rv 0.9.9 -ts --plugin -f prettier,eslint`,
true,
{
cwd: FOLDER_PROJECTS_TEST_PATH
}
)

const md_file_path = fs
.access(path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'DEVELOPMENT.md'))
.then(() => true)
.catch(() => false)
const isPlugin = (
await fs.readFile(path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'config', 'robo.mjs'))
).includes("type: 'plugin'")
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (md_file_path && featureInstalled) {
expect(isPlugin).toBeTruthy()
}
}, 20000)

// Package Managers

/*it(`Standard TypeScript But PNPX: TypeScript, recommended features, and credentials.`, async () => {
const project_name = "TRFC"
await exec(`pnpx ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`);

const isCredentialsSet = await areCredentialsSet(env_file_path);
const featureInstalled = areFeaturesInstalled(["prettier.config.mjs", ".eslintrc.json"], project_name);

if(featureInstalled){
expect(isCredentialsSet).toBeTruthy();
}
}, 20000)

// yarn being different we gotta use "robo" and not "create-robo".

it(`Standard TypeScript But Yarn create: TypeScript, recommended features, and credentials.`, async () => {
const project_name = "YTRFC";
await exec(`yarn create ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`);

const isCredentialsSet = await areCredentialsSet(env_file_path);
const featureInstalled = areFeaturesInstalled(["prettier.config.mjs", ".eslintrc.json"], project_name);

if(featureInstalled){
expect(isCredentialsSet).toBeTruthy();
}
}, 20000)

// Bun X

it(`Standard TypeScript But BUNX: TypeScript, recommended features, and credentials.`, async () => {
const project_name = "BXTRFC";
await exec(`bunx ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`);

const isCredentialsSet = await areCredentialsSet(env_file_path);
const featureInstalled = areFeaturesInstalled(["prettier.config.mjs", ".eslintrc.json"], project_name);

if(featureInstalled){
expect(isCredentialsSet).toBeTruthy();
}
}, 20000)*/

// Specials !

it(`Plugins: Same as Standard TS but with the api and ai plugins installed.`, async () => {
const project_name = 'STWAPIAI'
await exec(
`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -rv 0.9.9 -ts -f prettier,eslint --plugins @roboplay/plugin-ai @roboplay/plugin-api`,
true,
{
cwd: FOLDER_PROJECTS_TEST_PATH
}
)

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)
const isCredentialsSet = await areCredentialsSet(env_file_path)

const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)
const pluginsInstalled = await arePluginsInstalled(['plugin-ai', 'plugin-api'], project_name)

if (featureInstalled && isCredentialsSet) {
expect(pluginsInstalled).toBeTruthy()
}
}, 20000)

it(`Robo Version: Same as Standard TS but using a specific version of Robo.js.`, async () => {
const project_name = 'STWV'
const rv = '0.9.0'
await exec(`node ${LOCAL_COPY_OF_ROBO_CREATE_PATH} ${project_name} -ts -rv ${rv} -f prettier,eslint`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)
const isCredentialsSet = await areCredentialsSet(env_file_path)

const roboVersion = JSON.parse(
await fs.readFile(path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'package.json'), 'utf-8')
)['dependencies']['@roboplay/robo.js']
const featuresInstalled = await areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)

if (featuresInstalled && isCredentialsSet) {
expect(roboVersion).toBe(rv)
}
}, 20000)

it(`No Install: Same as Standard TS minus the installation of dependencies.`, async () => {
const project_name = 'STMI'
await exec(`bunx create-robo ${project_name} -ts -f prettier,eslint -ni`, true, {
cwd: FOLDER_PROJECTS_TEST_PATH
})

const env_file_path = path.join(FOLDER_PROJECTS_TEST_PATH, project_name, `.env`)

const isCredentialsSet = await areCredentialsSet(env_file_path)
const featureInstalled = areFeaturesInstalled(['prettier.config.mjs', '.eslintrc.json'], project_name)
const dependencies = JSON.parse(
await fs.readFile(path.join(FOLDER_PROJECTS_TEST_PATH, project_name, 'package.json'), 'utf-8')
)['dependencies']

if (featureInstalled && Object.keys(dependencies).length <= 0) {
expect(isCredentialsSet).toBeTruthy()
}
}, 20000)
})

function exec(command: string, passCreds: boolean, options?: SpawnOptions) {
return new Promise<void>((resolve, reject) => {
// Run command as child process
const args = command.split(' ')
const childProcess = spawn(args.shift(), args, {
...(options ?? {}),
env: { ...process.env, FORCE_COLOR: '1' },
stdio: 'pipe'
})

childProcess.stdout.on('data', (data: any) => {
const convertString = String.fromCharCode(...data)

if (convertString.includes('Client ID')) {
passCreds ? childProcess.stdin.write(`Credentials\n`) : childProcess.stdin.write(`\n`)
}
})

childProcess.stderr.on('data', function (data) {
console.log('stdout: ' + data)
})

// Resolve promise when child process exits
childProcess.on('close', (code) => {
if (code === 0) {
resolve()
} else {
reject(new Error(`Child process exited with code ${code}`))
}
})

// Or reject when it errors
childProcess.on('error', (error) => {
console.log(error)
reject(error)
})
})
}
7 changes: 7 additions & 0 deletions packages/create-robo/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
export default {
preset: 'ts-jest',
resolver: 'jest-resolver-enhanced',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.test.ts']
}
8 changes: 7 additions & 1 deletion packages/create-robo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
},
"scripts": {
"build": "tsup",
"dev": "chokidar \"src/**/*.ts\" -d 1000 -c \"pnpm build\" --initial"
"dev": "chokidar \"src/**/*.ts\" -d 1000 -c \"pnpm build\" --initial",
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
},
"bin": {
"create-robo": "dist/index.js"
Expand Down Expand Up @@ -49,10 +50,15 @@
"@roboplay/robo.js": "0.9.0",
"@types/async-retry": "^1.4.5",
"@types/inquirer": "^9.0.3",
"@types/jest": "^29.5.5",
"@types/mocha": "^10.0.6",
"@types/node": "^18.16.3",
"@types/tar": "^6.1.4",
"chokidar-cli": "^3.0.0",
"discord.js": "^14.10.2",
"jest": "^29.7.0",
"jest-resolver-enhanced": "^1.1.0",
"ts-jest": "^29.1.1",
"tsup": "6.7.0",
"typescript": "5.0.2"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/create-robo/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"include": ["src"],
"include": ["__tests__", "src"],
"compilerOptions": {
"target": "ESNext",
"module": "node16",
"lib": ["dom", "dom.iterable", "esnext"],
"types": ["node"],
"types": ["node", "jest"],
"baseUrl": ".",
"allowJs": true,
"skipLibCheck": true,
Expand Down
Loading