dbshift
Version:
A simple and powerful MySQL database migration tool inspired by Flyway
176 lines (142 loc) • 6.07 kB
JavaScript
const ConnectionTester = require('../../lib/utils/connectionTester');
const Database = require('../../lib/core/database');
// Mock Database
jest.mock('../../lib/core/database');
describe('ConnectionTester', () => {
let mockDatabase;
beforeEach(() => {
jest.clearAllMocks();
// Mock console methods to avoid clutter in tests
jest.spyOn(console, 'log').mockImplementation(() => {});
jest.spyOn(console, 'error').mockImplementation(() => {});
mockDatabase = {
connect: jest.fn(),
disconnect: jest.fn(),
connection: {
query: jest.fn()
}
};
Database.mockImplementation(() => mockDatabase);
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('testConnection', () => {
test('should successfully test connection', async () => {
// Setup mocks
mockDatabase.connection.query
.mockResolvedValueOnce([[{ test_connection: 1, mysql_version: '8.0.28' }]])
.mockResolvedValueOnce([[{ server_comment: 'MySQL Community Server' }]]);
const dbConfig = {
host: 'localhost',
user: 'root',
port: 3306,
password: 'password'
};
const result = await ConnectionTester.testConnection(dbConfig, { verbose: false });
expect(result.success).toBe(true);
expect(result.mysql_version).toBe('8.0.28');
expect(result.server_comment).toBe('MySQL Community Server');
expect(result.timing).toHaveProperty('connect');
expect(result.timing).toHaveProperty('query');
expect(result.timing).toHaveProperty('total');
expect(mockDatabase.connect).toHaveBeenCalledTimes(1);
expect(mockDatabase.disconnect).toHaveBeenCalledTimes(1);
expect(mockDatabase.connection.query).toHaveBeenCalledTimes(2);
});
test('should handle connection failure', async () => {
const connectionError = new Error('Connection refused');
connectionError.code = 'ECONNREFUSED';
mockDatabase.connect.mockRejectedValue(connectionError);
const dbConfig = {
host: 'invalid-host',
user: 'root',
port: 3306,
password: 'password'
};
await expect(ConnectionTester.testConnection(dbConfig, { verbose: false }))
.rejects.toThrow('Connection refused');
});
test('should test migration table when requested', async () => {
// Setup basic connection mocks
mockDatabase.connection.query
.mockResolvedValueOnce([[{ test_connection: 1, mysql_version: '8.0.28' }]])
.mockResolvedValueOnce([[{ server_comment: 'MySQL Community Server' }]]);
// Setup migration table test mocks
const mockMigrationTableQuery = jest.fn()
.mockResolvedValueOnce([[{ count: 1 }]]) // table exists
.mockResolvedValueOnce([[{ total_migrations: 5, completed_migrations: 3, pending_migrations: 2 }]]);
const mockMigrationDatabase = {
connect: jest.fn(),
disconnect: jest.fn(),
connection: {
query: mockMigrationTableQuery
}
};
// Mock Database constructor to return different instances
Database.mockImplementationOnce(() => mockDatabase)
.mockImplementationOnce(() => mockMigrationDatabase);
const dbConfig = {
host: 'localhost',
user: 'root',
port: 3306,
password: 'password'
};
const result = await ConnectionTester.testConnection(dbConfig, {
verbose: false,
testMigrationTable: true
});
expect(result.success).toBe(true);
expect(result.migration).toEqual({
table_exists: true,
total_migrations: 5,
completed_migrations: 3,
pending_migrations: 2
});
expect(mockMigrationDatabase.connect).toHaveBeenCalledTimes(1);
expect(mockMigrationDatabase.disconnect).toHaveBeenCalledTimes(1);
});
});
describe('testMigrationTableAccess', () => {
test('should handle non-existent migration table', async () => {
mockDatabase.connection.query.mockResolvedValueOnce([[{ count: 0 }]]); // table doesn't exist
const dbConfig = { host: 'localhost', user: 'root' };
const result = await ConnectionTester.testMigrationTableAccess(dbConfig, false);
expect(result.table_exists).toBe(false);
expect(result.total_migrations).toBe(0);
expect(result.completed_migrations).toBe(0);
expect(result.pending_migrations).toBe(0);
});
test('should get migration statistics when table exists', async () => {
mockDatabase.connection.query
.mockResolvedValueOnce([[{ count: 1 }]]) // table exists
.mockResolvedValueOnce([[{
total_migrations: 10,
completed_migrations: 8,
pending_migrations: 2
}]]);
const dbConfig = { host: 'localhost', user: 'root' };
const result = await ConnectionTester.testMigrationTableAccess(dbConfig, false);
expect(result.table_exists).toBe(true);
expect(result.total_migrations).toBe(10);
expect(result.completed_migrations).toBe(8);
expect(result.pending_migrations).toBe(2);
});
});
describe('showTroubleshootingSuggestions', () => {
test('should show appropriate suggestions for different error types', () => {
const logSpy = jest.spyOn(console, 'log');
// Test ECONNREFUSED error
const connRefusedError = new Error('Connection refused');
connRefusedError.code = 'ECONNREFUSED';
ConnectionTester.showTroubleshootingSuggestions(connRefusedError);
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Check if MySQL server is running'));
// Test ACCESS_DENIED error
logSpy.mockClear();
const accessDeniedError = new Error('Access denied');
accessDeniedError.code = 'ER_ACCESS_DENIED_ERROR';
ConnectionTester.showTroubleshootingSuggestions(accessDeniedError);
expect(logSpy).toHaveBeenCalledWith(expect.stringContaining('Check username and password'));
});
});
});