@heyputer/shell 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +9 -0
- package/.env.example +3 -0
- package/.github/workflows/npm-build.yml +34 -0
- package/.github/workflows/npm-publish.yml +50 -0
- package/.idx/dev.nix +53 -0
- package/CHANGELOG.md +292 -0
- package/LICENSE.md +21 -0
- package/README.md +18 -0
- package/bin/index.js +258 -0
- package/package.json +58 -0
- package/screenshot.png +0 -0
- package/src/commands/apps.js +356 -0
- package/src/commands/auth.js +195 -0
- package/src/commands/deploy.js +54 -0
- package/src/commands/files.js +1187 -0
- package/src/commands/init.js +322 -0
- package/src/commands/shell.js +61 -0
- package/src/commands/sites.js +169 -0
- package/src/commands/subdomains.js +95 -0
- package/src/commons.js +409 -0
- package/src/crypto.js +9 -0
- package/src/executor.js +386 -0
- package/src/modules/ErrorModule.js +20 -0
- package/src/modules/ProfileModule.js +334 -0
- package/src/modules/PuterModule.js +30 -0
- package/src/utils.js +135 -0
- package/tests/ErrorModule.test.js +42 -0
- package/tests/ProfileModule.test.js +274 -0
- package/tests/PuterModule.test.js +56 -0
- package/tests/apps.test.js +194 -0
- package/tests/commons.test.js +380 -0
- package/tests/deploy.test.js +84 -0
- package/tests/executor.test.js +52 -0
- package/tests/files.test.js +640 -0
- package/tests/login.test.js +206 -0
- package/tests/shell.test.js +184 -0
- package/tests/sites.test.js +67 -0
- package/tests/subdomains.test.js +90 -0
- package/tests/utils.test.js +193 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
login, logout, getUserInfo, isAuthenticated, getAuthToken, getCurrentUserName,
|
|
4
|
+
getUsageInfo
|
|
5
|
+
} from '../src/commands/auth.js';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import Conf from 'conf';
|
|
8
|
+
import { PROJECT_NAME } from '../src/commons.js';
|
|
9
|
+
import * as PuterModule from '../src/modules/PuterModule.js';
|
|
10
|
+
|
|
11
|
+
// Mock console to prevent actual logging
|
|
12
|
+
vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
13
|
+
vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
14
|
+
|
|
15
|
+
// Mock dependencies
|
|
16
|
+
vi.mock('inquirer');
|
|
17
|
+
vi.mock('chalk', () => ({
|
|
18
|
+
default: {
|
|
19
|
+
green: vi.fn(text => text),
|
|
20
|
+
red: vi.fn(text => text),
|
|
21
|
+
dim: vi.fn(text => text),
|
|
22
|
+
yellow: vi.fn(text => text),
|
|
23
|
+
cyan: vi.fn(text => text),
|
|
24
|
+
}
|
|
25
|
+
}));
|
|
26
|
+
vi.mock('../src/modules/PuterModule.js');
|
|
27
|
+
|
|
28
|
+
// Mock ProfileModule
|
|
29
|
+
const mockProfileModule = {
|
|
30
|
+
switchProfileWizard: vi.fn(),
|
|
31
|
+
getAuthToken: vi.fn(),
|
|
32
|
+
getCurrentProfile: vi.fn(),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
vi.mock('../src/modules/ProfileModule.js', () => ({
|
|
36
|
+
getProfileModule: vi.fn(() => mockProfileModule),
|
|
37
|
+
initProfileModule: vi.fn(),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
// Create a mock spinner object
|
|
41
|
+
const mockSpinner = {
|
|
42
|
+
start: vi.fn().mockReturnThis(),
|
|
43
|
+
succeed: vi.fn().mockReturnThis(),
|
|
44
|
+
fail: vi.fn().mockReturnThis(),
|
|
45
|
+
info: vi.fn().mockReturnThis(),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Mock ora
|
|
49
|
+
vi.mock('ora', () => ({
|
|
50
|
+
default: vi.fn(() => mockSpinner)
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
// Mock Conf
|
|
54
|
+
vi.mock('conf', () => {
|
|
55
|
+
return {
|
|
56
|
+
default: vi.fn().mockImplementation(() => ({
|
|
57
|
+
set: vi.fn(),
|
|
58
|
+
get: vi.fn(),
|
|
59
|
+
clear: vi.fn(),
|
|
60
|
+
})),
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe('auth.js', () => {
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
vi.clearAllMocks();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
describe('login', () => {
|
|
70
|
+
it('should login successfully with valid credentials', async () => {
|
|
71
|
+
await login({});
|
|
72
|
+
expect(mockProfileModule.switchProfileWizard).toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should fail login with invalid credentials', async () => {
|
|
76
|
+
mockProfileModule.switchProfileWizard.mockRejectedValue(new Error('Invalid credentials'));
|
|
77
|
+
await expect(login({})).rejects.toThrow('Invalid credentials');
|
|
78
|
+
expect(mockProfileModule.switchProfileWizard).toHaveBeenCalled();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it.skip('should handle login error', async () => {
|
|
82
|
+
// This test needs to be updated to reflect the new login flow
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
describe('logout', () => {
|
|
88
|
+
let config;
|
|
89
|
+
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
vi.clearAllMocks();
|
|
92
|
+
config = new Conf({ projectName: PROJECT_NAME });
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it.skip('should logout successfully', async () => {
|
|
96
|
+
// This test needs to be updated to reflect the new login flow
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle already logged out', async () => {
|
|
100
|
+
config.get = vi.fn().mockReturnValue(null);
|
|
101
|
+
await logout();
|
|
102
|
+
expect(mockSpinner.info).toHaveBeenCalledWith(chalk.yellow('Already logged out'));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it.skip('should handle logout error', async () => {
|
|
106
|
+
// This test needs to be updated to reflect the new login flow
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
describe('getUserInfo', () => {
|
|
113
|
+
const mockPuter = {
|
|
114
|
+
auth: {
|
|
115
|
+
getUser: vi.fn(),
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
beforeEach(() => {
|
|
120
|
+
vi.spyOn(PuterModule, 'getPuter').mockReturnValue(mockPuter);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should fetch user info successfully', async () => {
|
|
124
|
+
mockPuter.auth.getUser.mockResolvedValue({
|
|
125
|
+
username: 'testuser',
|
|
126
|
+
uuid: 'testuuid',
|
|
127
|
+
email: 'test@puter.com',
|
|
128
|
+
email_confirmed: true,
|
|
129
|
+
is_temp: false,
|
|
130
|
+
human_readable_age: '1 day',
|
|
131
|
+
feature_flags: {},
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await getUserInfo();
|
|
135
|
+
|
|
136
|
+
expect(mockPuter.auth.getUser).toHaveBeenCalled();
|
|
137
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('User Information:'));
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should handle fetch user info error', async () => {
|
|
141
|
+
mockPuter.auth.getUser.mockRejectedValue(new Error('Network error'));
|
|
142
|
+
await getUserInfo();
|
|
143
|
+
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Failed to get user info.'));
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
describe('Authentication', () => {
|
|
149
|
+
it('should return false if auth token does not exist', () => {
|
|
150
|
+
mockProfileModule.getAuthToken.mockReturnValue(null);
|
|
151
|
+
const result = isAuthenticated();
|
|
152
|
+
expect(result).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should return null if the auth_token is not defined', () => {
|
|
156
|
+
mockProfileModule.getAuthToken.mockReturnValue(null);
|
|
157
|
+
const result = getAuthToken();
|
|
158
|
+
expect(result).toBe(null);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should return the current username if it is defined', () => {
|
|
162
|
+
mockProfileModule.getCurrentProfile.mockReturnValue({ username: 'testuser' });
|
|
163
|
+
const result = getCurrentUserName();
|
|
164
|
+
expect(result).toBe('testuser');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('getUsageInfo', () => {
|
|
170
|
+
const mockPuter = {
|
|
171
|
+
auth: {
|
|
172
|
+
getMonthlyUsage: vi.fn(),
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
beforeEach(() => {
|
|
177
|
+
vi.spyOn(PuterModule, 'getPuter').mockReturnValue(mockPuter);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should fetch usage info successfully', async () => {
|
|
181
|
+
mockPuter.auth.getMonthlyUsage.mockResolvedValue({
|
|
182
|
+
allowanceInfo: {
|
|
183
|
+
monthUsageAllowance: 1000,
|
|
184
|
+
remaining: 500,
|
|
185
|
+
},
|
|
186
|
+
usage: {
|
|
187
|
+
total: 500,
|
|
188
|
+
},
|
|
189
|
+
appTotals: {},
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
await getUsageInfo();
|
|
193
|
+
|
|
194
|
+
expect(mockPuter.auth.getMonthlyUsage).toHaveBeenCalled();
|
|
195
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Allowance Information:'));
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should handle fetch usage info error', async () => {
|
|
199
|
+
mockPuter.auth.getMonthlyUsage.mockRejectedValue(new Error('Network error'));
|
|
200
|
+
await getUsageInfo();
|
|
201
|
+
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Failed to fetch usage information.'));
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
});
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execCommand, getPrompt } from '../src/executor.js';
|
|
3
|
+
import { getProfileModule } from '../src/modules/ProfileModule.js';
|
|
4
|
+
import readline from 'node:readline';
|
|
5
|
+
|
|
6
|
+
vi.mock('../src/executor.js');
|
|
7
|
+
vi.mock('../src/modules/ProfileModule.js');
|
|
8
|
+
vi.mock('node:readline');
|
|
9
|
+
vi.mock('conf', () => {
|
|
10
|
+
const Conf = vi.fn(() => ({
|
|
11
|
+
get: vi.fn(),
|
|
12
|
+
set: vi.fn(),
|
|
13
|
+
}));
|
|
14
|
+
return { default: Conf };
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
vi.spyOn(console, 'log').mockImplementation(() => { });
|
|
18
|
+
vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
19
|
+
|
|
20
|
+
let updatePrompt;
|
|
21
|
+
let startShell;
|
|
22
|
+
|
|
23
|
+
beforeEach(async () => {
|
|
24
|
+
vi.resetModules();
|
|
25
|
+
vi.clearAllMocks();
|
|
26
|
+
|
|
27
|
+
vi.mocked(getPrompt).mockReturnValue('puter@/> ');
|
|
28
|
+
vi.mocked(getProfileModule).mockReturnValue({
|
|
29
|
+
checkLogin: vi.fn(),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const mockOn = vi.fn().mockReturnThis();
|
|
33
|
+
vi.mocked(readline.createInterface).mockReturnValue({
|
|
34
|
+
setPrompt: vi.fn(),
|
|
35
|
+
prompt: vi.fn(),
|
|
36
|
+
on: mockOn,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const module = await import('../src/commands/shell.js');
|
|
40
|
+
updatePrompt = module.updatePrompt;
|
|
41
|
+
startShell = module.startShell;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('updatePrompt', () => {
|
|
45
|
+
it('should call rl.setPrompt with getPrompt result', async () => {
|
|
46
|
+
await startShell();
|
|
47
|
+
const rl = readline.createInterface.mock.results[0].value;
|
|
48
|
+
rl.setPrompt.mockClear();
|
|
49
|
+
|
|
50
|
+
updatePrompt('/test/path');
|
|
51
|
+
|
|
52
|
+
expect(rl.setPrompt).toHaveBeenCalledWith('puter@/> ');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('startShell', () => {
|
|
57
|
+
it('should call checkLogin', async () => {
|
|
58
|
+
await startShell();
|
|
59
|
+
expect(getProfileModule().checkLogin).toHaveBeenCalled();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('with command argument', () => {
|
|
63
|
+
let mockExit;
|
|
64
|
+
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
|
|
67
|
+
throw new Error('process.exit called');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
mockExit.mockRestore();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should execute command and exit when command is provided', async () => {
|
|
76
|
+
await expect(startShell('help')).rejects.toThrow('process.exit called');
|
|
77
|
+
expect(execCommand).toHaveBeenCalledWith('help');
|
|
78
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should not create readline interface when command is provided', async () => {
|
|
82
|
+
vi.mocked(readline.createInterface).mockClear();
|
|
83
|
+
await expect(startShell('help')).rejects.toThrow('process.exit called');
|
|
84
|
+
expect(readline.createInterface).not.toHaveBeenCalled();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('without command argument (interactive mode)', () => {
|
|
89
|
+
it('should create readline interface', async () => {
|
|
90
|
+
await startShell();
|
|
91
|
+
expect(readline.createInterface).toHaveBeenCalledWith({
|
|
92
|
+
input: process.stdin,
|
|
93
|
+
output: process.stdout,
|
|
94
|
+
prompt: null,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should display welcome message', async () => {
|
|
99
|
+
await startShell();
|
|
100
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Welcome to Puter-CLI'));
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should set prompt and call prompt()', async () => {
|
|
104
|
+
await startShell();
|
|
105
|
+
const rl = readline.createInterface.mock.results[0].value;
|
|
106
|
+
expect(rl.setPrompt).toHaveBeenCalledWith('puter@/> ');
|
|
107
|
+
expect(rl.prompt).toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should register line and close event handlers', async () => {
|
|
111
|
+
await startShell();
|
|
112
|
+
const rl = readline.createInterface.mock.results[0].value;
|
|
113
|
+
expect(rl.on).toHaveBeenCalledWith('line', expect.any(Function));
|
|
114
|
+
expect(rl.on).toHaveBeenCalledWith('close', expect.any(Function));
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('line event handler', () => {
|
|
119
|
+
let lineHandler;
|
|
120
|
+
let rl;
|
|
121
|
+
|
|
122
|
+
beforeEach(async () => {
|
|
123
|
+
await startShell();
|
|
124
|
+
rl = readline.createInterface.mock.results[0].value;
|
|
125
|
+
lineHandler = rl.on.mock.calls.find(call => call[0] === 'line')[1];
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should execute trimmed command', async () => {
|
|
129
|
+
await lineHandler(' ls ');
|
|
130
|
+
expect(execCommand).toHaveBeenCalledWith('ls');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should not execute empty line', async () => {
|
|
134
|
+
vi.mocked(execCommand).mockClear();
|
|
135
|
+
await lineHandler(' ');
|
|
136
|
+
expect(execCommand).not.toHaveBeenCalled();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should call prompt after executing command', async () => {
|
|
140
|
+
rl.prompt.mockClear();
|
|
141
|
+
await lineHandler('ls');
|
|
142
|
+
expect(rl.prompt).toHaveBeenCalled();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should log error message when execCommand throws', async () => {
|
|
146
|
+
vi.mocked(execCommand).mockRejectedValueOnce(new Error('Command failed'));
|
|
147
|
+
await lineHandler('badcmd');
|
|
148
|
+
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Command failed'));
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should still call prompt after error', async () => {
|
|
152
|
+
vi.mocked(execCommand).mockRejectedValueOnce(new Error('Command failed'));
|
|
153
|
+
rl.prompt.mockClear();
|
|
154
|
+
await lineHandler('badcmd');
|
|
155
|
+
expect(rl.prompt).toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('close event handler', () => {
|
|
160
|
+
let closeHandler;
|
|
161
|
+
let mockExit;
|
|
162
|
+
|
|
163
|
+
beforeEach(async () => {
|
|
164
|
+
mockExit = vi.spyOn(process, 'exit').mockImplementation(() => { });
|
|
165
|
+
await startShell();
|
|
166
|
+
const rl = readline.createInterface.mock.results[0].value;
|
|
167
|
+
closeHandler = rl.on.mock.calls.find(call => call[0] === 'close')[1];
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
afterEach(() => {
|
|
171
|
+
mockExit.mockRestore();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should display goodbye message', () => {
|
|
175
|
+
closeHandler();
|
|
176
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Goodbye'));
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('should exit with code 0', () => {
|
|
180
|
+
closeHandler();
|
|
181
|
+
expect(mockExit).toHaveBeenCalledWith(0);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { describe, vi, expect, it } from "vitest";
|
|
2
|
+
import { createSite, deleteSite, infoSite, listSites } from "../src/commands/sites";
|
|
3
|
+
import { createSubdomain, deleteSubdomain, getSubdomains } from "../src/commands/subdomains";
|
|
4
|
+
import { getPuter } from "../src/modules/PuterModule.js";
|
|
5
|
+
import { getCurrentDirectory } from "../src/commands/auth.js";
|
|
6
|
+
|
|
7
|
+
vi.mock("../src/commands/subdomains")
|
|
8
|
+
vi.mock("../src/modules/PuterModule")
|
|
9
|
+
vi.mock('../src/commands/auth.js');
|
|
10
|
+
|
|
11
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
12
|
+
|
|
13
|
+
describe("listSites", () => {
|
|
14
|
+
it("should list sites successfully", async () => {
|
|
15
|
+
vi.mocked(getSubdomains).mockResolvedValue([{
|
|
16
|
+
uid: "123",
|
|
17
|
+
subdomain: "hehe.puter.site",
|
|
18
|
+
root_dir: { path: "/some/path" },
|
|
19
|
+
}])
|
|
20
|
+
await listSites();
|
|
21
|
+
expect(getSubdomains).toHaveBeenCalled();
|
|
22
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Total Sites: 1"))
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe("infoSite", () => {
|
|
27
|
+
it("should get site info successfully", async () => {
|
|
28
|
+
const mockHostingGet = vi.fn().mockResolvedValue({
|
|
29
|
+
uid: "123",
|
|
30
|
+
subdomain: "hehe.puter.site",
|
|
31
|
+
root_dir: { path: "/some/path" },
|
|
32
|
+
});
|
|
33
|
+
vi.mocked(getPuter).mockReturnValue({
|
|
34
|
+
hosting: {
|
|
35
|
+
get: mockHostingGet
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
await infoSite(["hehe.puter.site"])
|
|
40
|
+
expect(getPuter).toHaveBeenCalled();
|
|
41
|
+
expect(mockHostingGet).toHaveBeenCalled();
|
|
42
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("hehe.puter.site"))
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe("deleteSite", () => {
|
|
47
|
+
it("should delete site successfully", async () => {
|
|
48
|
+
vi.mocked(deleteSubdomain)
|
|
49
|
+
const result = await deleteSite(["hehe.puter.site"]);
|
|
50
|
+
expect(result).toBe(true);
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
describe("createSite", () => {
|
|
55
|
+
it("should create site successfully", async () => {
|
|
56
|
+
vi.mocked(createSubdomain).mockResolvedValue({
|
|
57
|
+
uid: "123",
|
|
58
|
+
subdomain: "hehe.puter.site",
|
|
59
|
+
root_dir: { path: "/some/path" },
|
|
60
|
+
})
|
|
61
|
+
vi.mocked(getCurrentDirectory).mockReturnValue('/testuser');
|
|
62
|
+
const result = await createSite(["hehe hehe --subdomain=hehe"]);
|
|
63
|
+
expect(result).toMatchObject({
|
|
64
|
+
subdomain: "hehe.puter.site"
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { vi } from "vitest";
|
|
2
|
+
import { it } from "vitest";
|
|
3
|
+
import { describe } from "vitest";
|
|
4
|
+
import { createSubdomain, deleteSubdomain, getSubdomains, updateSubdomain } from "../src/commands/subdomains";
|
|
5
|
+
import { expect } from "vitest";
|
|
6
|
+
import { getPuter } from "../src/modules/PuterModule";
|
|
7
|
+
|
|
8
|
+
vi.mock("../src/modules/PuterModule")
|
|
9
|
+
vi.mock("conf", () => {
|
|
10
|
+
const Conf = vi.fn(() => ({
|
|
11
|
+
get: vi.fn(),
|
|
12
|
+
set: vi.fn(),
|
|
13
|
+
clear: vi.fn(),
|
|
14
|
+
}));
|
|
15
|
+
return { default: Conf };
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
vi.spyOn(console, "log").mockImplementation(() => { });
|
|
19
|
+
|
|
20
|
+
describe("getSubdomains", () => {
|
|
21
|
+
it("should get subdomains successfully", async () => {
|
|
22
|
+
const mockHostingList = vi.fn().mockResolvedValue([{
|
|
23
|
+
uid: "123",
|
|
24
|
+
subdomain: "hehe.puter.site",
|
|
25
|
+
root_dir: { path: "/some/path" },
|
|
26
|
+
}]);
|
|
27
|
+
vi.mocked(getPuter).mockReturnValue({
|
|
28
|
+
hosting: {
|
|
29
|
+
list: mockHostingList
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
const result = await getSubdomains();
|
|
33
|
+
expect(getPuter).toHaveBeenCalled();
|
|
34
|
+
expect(result).toHaveLength(1)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe("deleteSubdomain", () => {
|
|
39
|
+
it("should delete subdomain successfully", async () => {
|
|
40
|
+
const mockHostingDelete = vi.fn().mockResolvedValue(true);
|
|
41
|
+
vi.mocked(getPuter).mockReturnValue({
|
|
42
|
+
hosting: {
|
|
43
|
+
delete: mockHostingDelete
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
const result = await deleteSubdomain(["hehe.puter.site"]);
|
|
47
|
+
expect(result).toBe(true);
|
|
48
|
+
expect(console.log).toHaveBeenCalledWith(expect.stringContaining("Subdomain deleted successfully"));
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe("createSubdomain", () => {
|
|
53
|
+
it("should create subdomain successfully", async () => {
|
|
54
|
+
const mockHostingCreate = vi.fn().mockResolvedValue({
|
|
55
|
+
uid: "123",
|
|
56
|
+
subdomain: "hehe.puter.site",
|
|
57
|
+
root_dir: { path: "/some/path" },
|
|
58
|
+
});
|
|
59
|
+
vi.mocked(getPuter).mockReturnValue({
|
|
60
|
+
hosting: {
|
|
61
|
+
create: mockHostingCreate
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
const result = await createSubdomain("hehe", "/mydir")
|
|
65
|
+
expect(result).toMatchObject({
|
|
66
|
+
subdomain: "hehe.puter.site"
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe("updateSubdomain", () => {
|
|
72
|
+
it("should update subdomain successfully", async () => {
|
|
73
|
+
const mockHostingUpdate = vi.fn().mockResolvedValue({
|
|
74
|
+
uid: "123",
|
|
75
|
+
subdomain: "hehe.puter.site",
|
|
76
|
+
root_dir: { path: "/newdir" },
|
|
77
|
+
});
|
|
78
|
+
vi.mocked(getPuter).mockReturnValue({
|
|
79
|
+
hosting: {
|
|
80
|
+
update: mockHostingUpdate
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
const result = await updateSubdomain("hehe", "/newdir")
|
|
84
|
+
expect(result).toMatchObject({
|
|
85
|
+
root_dir: {
|
|
86
|
+
path: "/newdir"
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
})
|