create-datadao
Version:
A CLI tool to generate and deploy DataDAOs on the Vana network
346 lines (288 loc) • 12.4 kB
JavaScript
const { setupConfig } = require('../config');
const { createMockInquirer, createMockWallet } = require('../../__tests__/mocks/factories');
// Mock dependencies
jest.mock('../wallet');
jest.mock('../validation');
jest.mock('inquirer');
jest.mock('chalk', () => ({
blue: jest.fn((text) => text),
yellow: jest.fn((text) => text),
cyan: jest.fn((text) => text),
green: jest.fn((text) => text),
red: jest.fn((text) => text),
}));
const { deriveWalletFromPrivateKey } = require('../wallet');
const { validatePrivateKey, normalizePrivateKey } = require('../validation');
const inquirer = require('inquirer');
describe('Config Functions', () => {
let originalConsoleLog;
beforeAll(() => {
originalConsoleLog = console.log;
console.log = jest.fn();
});
afterAll(() => {
console.log = originalConsoleLog;
});
beforeEach(() => {
jest.clearAllMocks();
// Setup default mocks
validatePrivateKey.mockReturnValue(true);
normalizePrivateKey.mockImplementation((key) => key.startsWith('0x') ? key : '0x' + key);
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
});
describe('setupConfig', () => {
test('collects complete configuration successfully', async () => {
const mockResponses = {
dlpName: 'TestDAO',
tokenName: 'TestToken',
tokenSymbol: 'TEST',
privateKey: '0x1234567890123456789012345678901234567890123456789012345678901234',
pinataApiKey: 'test-pinata-key',
pinataApiSecret: 'test-pinata-secret',
googleClientId: 'test-client-id',
googleClientSecret: 'test-client-secret',
githubUsername: 'test-user'
};
inquirer.prompt.mockImplementation((questions) => {
const answers = {};
for (const question of Array.isArray(questions) ? questions : [questions]) {
answers[question.name] = mockResponses[question.name] || question.default || '';
}
return Promise.resolve(answers);
});
const mockWallet = createMockWallet();
deriveWalletFromPrivateKey.mockReturnValue(mockWallet);
const result = await setupConfig();
expect(result).toEqual({
dlpName: 'TestDAO',
tokenName: 'TestToken',
tokenSymbol: 'TEST',
privateKey: '0x1234567890123456789012345678901234567890123456789012345678901234',
address: mockWallet.address,
publicKey: mockWallet.publicKey,
pinataApiKey: 'test-pinata-key',
pinataApiSecret: 'test-pinata-secret',
googleClientId: 'test-client-id',
googleClientSecret: 'test-client-secret',
githubUsername: 'test-user',
network: 'moksha',
rpcUrl: 'https://rpc.moksha.vana.org',
chainId: 14800
});
expect(normalizePrivateKey).toHaveBeenCalledWith(mockResponses.privateKey);
expect(deriveWalletFromPrivateKey).toHaveBeenCalledWith(mockResponses.privateKey);
});
test('uses default values when no input provided', async () => {
inquirer.prompt.mockImplementation((questions) => {
const answers = {};
for (const question of Array.isArray(questions) ? questions : [questions]) {
answers[question.name] = question.default || '';
}
return Promise.resolve(answers);
});
const mockWallet = createMockWallet();
deriveWalletFromPrivateKey.mockReturnValue(mockWallet);
const result = await setupConfig();
expect(result.dlpName).toBe('MyDataDAO');
expect(result.tokenName).toBe('MyDataToken');
expect(result.tokenSymbol).toBe('MDT');
expect(result.network).toBe('moksha');
expect(result.rpcUrl).toBe('https://rpc.moksha.vana.org');
expect(result.chainId).toBe(14800);
});
test('normalizes private key during collection', async () => {
const privateKeyWithoutPrefix = '1234567890123456789012345678901234567890123456789012345678901234';
const privateKeyWithPrefix = '0x1234567890123456789012345678901234567890123456789012345678901234';
inquirer.prompt.mockImplementation((questions) => {
const answers = {};
for (const question of Array.isArray(questions) ? questions : [questions]) {
if (question.name === 'privateKey') {
answers[question.name] = privateKeyWithoutPrefix;
} else {
answers[question.name] = question.default || '';
}
}
return Promise.resolve(answers);
});
normalizePrivateKey.mockReturnValue(privateKeyWithPrefix);
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
const result = await setupConfig();
expect(normalizePrivateKey).toHaveBeenCalledWith(privateKeyWithoutPrefix);
expect(deriveWalletFromPrivateKey).toHaveBeenCalledWith(privateKeyWithPrefix);
expect(result.privateKey).toBe(privateKeyWithPrefix);
});
test('validates private key input', async () => {
// First call should fail validation, second should pass
let callCount = 0;
validatePrivateKey
.mockImplementationOnce(() => 'Invalid private key format')
.mockImplementationOnce(() => true);
inquirer.prompt.mockImplementation((questions) => {
const questionsArray = Array.isArray(questions) ? questions : [questions];
const privateKeyQuestion = questionsArray.find(q => q.name === 'privateKey');
if (privateKeyQuestion && privateKeyQuestion.validate) {
// Test the validation function
const firstResult = privateKeyQuestion.validate('invalid-key');
expect(firstResult).toBe('Invalid private key format');
const secondResult = privateKeyQuestion.validate('0x1234567890123456789012345678901234567890123456789012345678901234');
expect(secondResult).toBe(true);
}
// Return answers for all questions
const answers = {};
for (const q of questionsArray) {
if (q.name === 'privateKey') {
answers[q.name] = '0x1234567890123456789012345678901234567890123456789012345678901234';
} else {
answers[q.name] = q.default || '';
}
}
return Promise.resolve(answers);
});
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
await setupConfig();
expect(validatePrivateKey).toHaveBeenCalledWith('invalid-key');
expect(validatePrivateKey).toHaveBeenCalledWith('0x1234567890123456789012345678901234567890123456789012345678901234');
});
test('handles wallet derivation errors gracefully', async () => {
inquirer.prompt.mockResolvedValue({
dlpName: 'TestDAO',
tokenName: 'TestToken',
tokenSymbol: 'TEST',
privateKey: '0x1234567890123456789012345678901234567890123456789012345678901234',
pinataApiKey: '',
pinataApiSecret: '',
googleClientId: '',
googleClientSecret: '',
githubUsername: 'test-user'
});
deriveWalletFromPrivateKey.mockImplementation(() => {
throw new Error('Failed to derive wallet');
});
await expect(setupConfig()).rejects.toThrow('Failed to derive wallet');
});
test('includes all required configuration sections', async () => {
inquirer.prompt.mockImplementation((questions) => {
// Verify we're prompted for all sections
const questionNames = Array.isArray(questions)
? questions.map(q => q.name)
: [questions.name];
return Promise.resolve(
questionNames.reduce((acc, name) => {
acc[name] = `test-${name}`;
return acc;
}, {})
);
});
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
const result = await setupConfig();
// Verify all required sections are present
expect(result).toHaveProperty('dlpName');
expect(result).toHaveProperty('tokenName');
expect(result).toHaveProperty('tokenSymbol');
expect(result).toHaveProperty('privateKey');
expect(result).toHaveProperty('address');
expect(result).toHaveProperty('publicKey');
expect(result).toHaveProperty('pinataApiKey');
expect(result).toHaveProperty('pinataApiSecret');
expect(result).toHaveProperty('googleClientId');
expect(result).toHaveProperty('googleClientSecret');
expect(result).toHaveProperty('githubUsername');
expect(result).toHaveProperty('network');
expect(result).toHaveProperty('rpcUrl');
expect(result).toHaveProperty('chainId');
});
test.skip('displays correct console messages', async () => {
// TODO: Fix chalk mock to work with console.log assertions
inquirer.prompt.mockResolvedValue({
dlpName: 'TestDAO',
tokenName: 'TestToken',
tokenSymbol: 'TEST',
privateKey: '0x1234567890123456789012345678901234567890123456789012345678901234',
pinataApiKey: '',
pinataApiSecret: '',
googleClientId: '',
googleClientSecret: '',
githubUsername: 'test-user'
});
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
await setupConfig();
// Debug: see what console.log was actually called with
console.log.mock.calls.forEach((call, index) => {
console.error(`Call ${index}:`, call);
});
// Verify console.log was called with expected messages
expect(console.log).toHaveBeenCalledWith(
expect.stringContaining('Please provide the following information')
);
expect(console.log).toHaveBeenCalledWith(
expect.stringContaining('Wallet Configuration:')
);
expect(console.log).toHaveBeenCalledWith(
expect.stringContaining('External Services:')
);
expect(console.log).toHaveBeenCalledWith(
expect.stringContaining('GitHub Integration:')
);
});
test('handles empty optional fields', async () => {
inquirer.prompt.mockResolvedValue({
dlpName: 'TestDAO',
tokenName: 'TestToken',
tokenSymbol: 'TEST',
privateKey: '0x1234567890123456789012345678901234567890123456789012345678901234',
pinataApiKey: '',
pinataApiSecret: '',
googleClientId: '',
googleClientSecret: '',
githubUsername: 'test-user'
});
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
const result = await setupConfig();
expect(result.pinataApiKey).toBe('');
expect(result.pinataApiSecret).toBe('');
expect(result.googleClientId).toBe('');
expect(result.googleClientSecret).toBe('');
});
test('validates GitHub username is required', async () => {
let githubQuestion = null;
inquirer.prompt.mockImplementation((questions) => {
const questionsArray = Array.isArray(questions) ? questions : [questions];
const githubQ = questionsArray.find(q => q.name === 'githubUsername');
if (githubQ) {
githubQuestion = githubQ;
// Test validation
expect(githubQ.validate('')).toBe('GitHub username is required');
expect(githubQ.validate('test-user')).toBe(true);
}
return Promise.resolve(
questionsArray.reduce((acc, q) => {
acc[q.name] = q.name === 'githubUsername' ? 'test-user' : (q.default || '');
return acc;
}, {})
);
});
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
await setupConfig();
expect(githubQuestion).toBeTruthy();
expect(githubQuestion.validate).toBeDefined();
});
test('includes network configuration', async () => {
inquirer.prompt.mockResolvedValue({
dlpName: 'TestDAO',
tokenName: 'TestToken',
tokenSymbol: 'TEST',
privateKey: '0x1234567890123456789012345678901234567890123456789012345678901234',
pinataApiKey: '',
pinataApiSecret: '',
googleClientId: '',
googleClientSecret: '',
githubUsername: 'test-user'
});
deriveWalletFromPrivateKey.mockReturnValue(createMockWallet());
const result = await setupConfig();
expect(result.network).toBe('moksha');
expect(result.rpcUrl).toBe('https://rpc.moksha.vana.org');
expect(result.chainId).toBe(14800);
});
});
});