Skip to content

Commit 89385b8

Browse files
update validation messages. refresh unit tests
1 parent 7cfd2e9 commit 89385b8

File tree

7 files changed

+73
-31
lines changed

7 files changed

+73
-31
lines changed

cli/src/commands/deploy/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,9 @@ export default class DeployAll extends CloudInstanceCommand {
251251
});
252252

253253
if (!validation) {
254-
await new Promise((resolve) => setTimeout(resolve, 1000));
254+
await new Promise((resolve) => {
255+
setTimeout(resolve, 1000);
256+
});
255257
continue;
256258
}
257259

cli/src/commands/validate.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ async function runSyncRulesTestCloud(project: CloudProject): Promise<ValidationT
109109
}
110110

111111
const client = createCloudClient();
112+
112113
try {
113114
const result = await client.validateSyncRules({
114115
app_id: project.linked.project_id,

cli/test/commands/deploy.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,31 @@
11
import { Config } from '@oclif/core';
22
import { captureOutput, runCommand } from '@oclif/test';
33
import { CLI_FILENAME, SERVICE_FILENAME } from '@powersync/cli-core';
4-
import { PowerSyncManagementClient } from '@powersync/management-client';
54
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
65
import { tmpdir } from 'node:os';
76
import { join } from 'node:path';
8-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
7+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
98

109
import DeployCommand from '../../src/commands/deploy/index.js';
1110
import { root } from '../helpers/root.js';
12-
13-
const mockGetInstanceConfig = vi.fn();
14-
const mockDeployInstance = vi.fn();
15-
const mockGetInstanceStatus = vi.fn();
11+
import { managementClientMock, resetManagementClientMocks } from '../setup.js';
1612

1713
/** Run deploy by instantiating the command and calling .run() so the spy on createCloudClient applies. */
1814
async function runDeployDirect(opts?: { directory?: string }) {
1915
const directory = opts?.directory ?? PROJECT_DIR;
2016
const config = await Config.load({ root });
2117
const cmd = new DeployCommand(['--directory', directory], config);
22-
cmd.client = {
23-
deployInstance: mockDeployInstance,
24-
getInstanceConfig: mockGetInstanceConfig,
25-
getInstanceStatus: mockGetInstanceStatus
26-
} as unknown as PowerSyncManagementClient;
18+
cmd.client = managementClientMock as unknown as DeployCommand['client'];
2719
return captureOutput(() => cmd.run());
2820
}
2921

3022
const PROJECT_DIR = 'powersync';
3123

3224
function writeServiceYaml(projectDir: string, type: 'cloud' | 'self-hosted') {
33-
const content = type === 'cloud' ? '_type: cloud\nname: test-instance\nregion: us\n' : `_type: ${type}\nregion: us\n`;
25+
const content =
26+
type === 'cloud'
27+
? '_type: cloud\nname: test-instance\nregion: us\nreplication:\n connections:\n - name: default\n type: postgresql\n uri: postgres://user:pass@host/db\n'
28+
: `_type: ${type}\nregion: us\n`;
3429
writeFileSync(join(projectDir, SERVICE_FILENAME), content, 'utf8');
3530
}
3631

@@ -45,15 +40,20 @@ describe('deploy', () => {
4540
let origPsToken: string | undefined;
4641

4742
beforeEach(() => {
43+
resetManagementClientMocks();
44+
4845
origCwd = process.cwd();
4946
origPsToken = process.env.TOKEN;
5047
tmpDir = mkdtempSync(join(tmpdir(), 'deploy-test-'));
5148
process.chdir(tmpDir);
5249
process.env.TOKEN = 'test-token';
53-
mockGetInstanceConfig.mockReset();
54-
mockDeployInstance.mockReset();
55-
mockGetInstanceStatus.mockReset();
56-
mockGetInstanceConfig.mockRejectedValue(new Error('network error'));
50+
managementClientMock.getInstanceConfig.mockResolvedValue({
51+
config: { region: 'us', replication: { connections: [{ name: 'default', type: 'postgresql' }] } },
52+
name: 'test-instance',
53+
sync_rules: ''
54+
});
55+
managementClientMock.getInstanceStatus.mockResolvedValue({ operations: [], provisioned: true });
56+
managementClientMock.deployInstance.mockRejectedValue(new Error('network error'));
5757
});
5858

5959
afterEach(() => {

cli/test/commands/destroy.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { join } from 'node:path';
55
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
66

77
import { root } from '../helpers/root.js';
8+
import { resetManagementClientMocks } from '../setup.js';
89

910
const CLI_FILENAME = 'cli.yaml';
1011
const PROJECT_DIR = 'powersync';
@@ -25,6 +26,8 @@ describe('destroy', () => {
2526
let origPsToken: string | undefined;
2627

2728
beforeEach(() => {
29+
resetManagementClientMocks();
30+
2831
origCwd = process.cwd();
2932
origPsToken = process.env.TOKEN;
3033
tmpDir = mkdtempSync(join(tmpdir(), 'destroy-test-'));

cli/test/commands/fetch/config.test.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
import { Config } from '@oclif/core';
22
import { captureOutput, runCommand } from '@oclif/test';
3-
import { PowerSyncManagementClient } from '@powersync/management-client';
43
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
54
import { tmpdir } from 'node:os';
65
import { join } from 'node:path';
7-
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
6+
import { afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
87

98
import FetchConfigCommand from '../../../src/commands/fetch/config.js';
109
import { root } from '../../helpers/root.js';
10+
import { managementClientMock, resetManagementClientMocks } from '../../setup.js';
1111

1212
const PROJECT_DIR = 'powersync';
1313
const SERVICE_FILENAME = 'service.yaml';
1414

1515
/** Minimal valid cloud config decodable by ServiceCloudConfig. */
1616
const MOCK_CONFIG = { _type: 'cloud' as const, name: 'test-instance', region: 'us' };
1717

18-
const mockCloudClient = {
19-
deployInstance: vi.fn(),
20-
getInstanceConfig: vi.fn()
21-
};
22-
2318
function writeServiceYaml(projectDir: string, type: 'cloud' | 'self-hosted') {
2419
writeFileSync(join(projectDir, SERVICE_FILENAME), `_type: ${type}\nregion: us\n`, 'utf8');
2520
}
@@ -38,16 +33,18 @@ describe('fetch config', () => {
3833
const args = ['--directory', directory];
3934
if (opts?.output) args.push('--output', opts.output);
4035
const cmd = new FetchConfigCommand(args, oclifConfig);
41-
cmd.client = mockCloudClient as unknown as PowerSyncManagementClient;
36+
cmd.client = managementClientMock as unknown as FetchConfigCommand['client'];
4237
return captureOutput(() => cmd.run());
4338
}
4439

4540
beforeEach(() => {
41+
resetManagementClientMocks();
42+
4643
origCwd = process.cwd();
4744
tmpDir = mkdtempSync(join(tmpdir(), 'fetch-config-test-'));
4845
process.chdir(tmpDir);
49-
mockCloudClient.getInstanceConfig.mockReset();
50-
mockCloudClient.getInstanceConfig.mockRejectedValue(new Error('network error'));
46+
managementClientMock.getInstanceConfig.mockReset();
47+
managementClientMock.getInstanceConfig.mockRejectedValue(new Error('network error'));
5148
});
5249

5350
afterEach(() => {
@@ -89,7 +86,7 @@ describe('fetch config', () => {
8986
});
9087

9188
it('default output is yaml and prints fetched object (config + optional syncRules) to stdout', async () => {
92-
mockCloudClient.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG });
89+
managementClientMock.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG });
9390
const result = await runFetchConfigDirect();
9491
expect(result.error).toBeUndefined();
9592
expect(result.stdout).toContain('config:');
@@ -98,7 +95,7 @@ describe('fetch config', () => {
9895
});
9996

10097
it('--output yaml prints fetched object as YAML to stdout', async () => {
101-
mockCloudClient.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG });
98+
managementClientMock.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG });
10299
const result = await runFetchConfigDirect({ output: 'yaml' });
103100
expect(result.error).toBeUndefined();
104101
expect(result.stdout).toContain('config:');
@@ -107,7 +104,7 @@ describe('fetch config', () => {
107104
});
108105

109106
it('--output json prints fetched object (config, syncRules) as JSON to stdout', async () => {
110-
mockCloudClient.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG });
107+
managementClientMock.getInstanceConfig.mockResolvedValueOnce({ config: MOCK_CONFIG });
111108
const result = await runFetchConfigDirect({ output: 'json' });
112109
expect(result.error).toBeUndefined();
113110
const parsed = JSON.parse(result.stdout) as { config: typeof MOCK_CONFIG };
@@ -116,7 +113,7 @@ describe('fetch config', () => {
116113

117114
it('--output json includes syncRules when returned', async () => {
118115
const syncRules = 'bucket_definitions: []\n';
119-
mockCloudClient.getInstanceConfig.mockResolvedValueOnce({
116+
managementClientMock.getInstanceConfig.mockResolvedValueOnce({
120117
config: MOCK_CONFIG,
121118
sync_rules: syncRules
122119
} as { config: typeof MOCK_CONFIG; sync_rules: string });

cli/test/commands/stop.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { join } from 'node:path';
55
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
66

77
import { root } from '../helpers/root.js';
8+
import { resetManagementClientMocks } from '../setup.js';
89

910
const CLI_FILENAME = 'cli.yaml';
1011
const PROJECT_DIR = 'powersync';
@@ -25,6 +26,8 @@ describe('stop', () => {
2526
let origPsToken: string | undefined;
2627

2728
beforeEach(() => {
29+
resetManagementClientMocks();
30+
2831
origCwd = process.cwd();
2932
origPsToken = process.env.TOKEN;
3033
tmpDir = mkdtempSync(join(tmpdir(), 'stop-test-'));

cli/test/setup.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,40 @@
11
import { Config } from '@oclif/core';
2+
import { vi } from 'vitest';
3+
4+
// Normalize env so tests don't inherit real linking values
5+
delete process.env.INSTANCE_ID;
6+
delete process.env.ORG_ID;
7+
delete process.env.PROJECT_ID;
8+
9+
export const managementClientMock = {
10+
deactivateInstance: vi.fn(),
11+
deployInstance: vi.fn(),
12+
getInstanceConfig: vi.fn(),
13+
getInstanceStatus: vi.fn(),
14+
listRegions: vi.fn(),
15+
testConnection: vi.fn(),
16+
validateSyncRules: vi.fn()
17+
};
18+
19+
export function resetManagementClientMocks(): void {
20+
managementClientMock.deactivateInstance.mockRejectedValue(new Error('mock deactivate failure'));
21+
managementClientMock.deployInstance.mockRejectedValue(new Error('mock deploy failure'));
22+
managementClientMock.getInstanceConfig.mockRejectedValue(new Error('mock getInstanceConfig failure'));
23+
managementClientMock.getInstanceStatus.mockRejectedValue(new Error('mock getInstanceStatus failure'));
24+
managementClientMock.listRegions.mockResolvedValue({ regions: [{ name: 'us' }] });
25+
managementClientMock.testConnection.mockResolvedValue({
26+
configuration: { success: true },
27+
connection: { reachable: true, success: true },
28+
success: true
29+
});
30+
managementClientMock.validateSyncRules.mockResolvedValue({ errors: [] });
31+
}
32+
33+
resetManagementClientMocks();
34+
35+
vi.mock('@powersync/management-client', () => ({
36+
PowerSyncManagementClient: vi.fn().mockImplementation(() => managementClientMock)
37+
}));
238

339
import { root } from './helpers/root.js';
440

0 commit comments

Comments
 (0)