Skip to content

Commit b37d677

Browse files
authored
feat: Add preload tests (#890)
* refactor: Move getWorkspaceConfigPath to config and getProjectInfoFs to project * fix: Add @vitest/coverage-v8 package * fix: Add tests * fix: Remove unrequired clearAllMocks * fix: types * fix: Update test dependencies
1 parent 41667dd commit b37d677

13 files changed

Lines changed: 2755 additions & 134 deletions

File tree

package-lock.json

Lines changed: 1231 additions & 94 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"eslint-plugin-import": "2.31.0",
1414
"happy-dom": "14.12.3",
1515
"nano-staged": "0.8.0",
16-
"playwright": "1.54.1",
16+
"playwright": "1.56.1",
1717
"prettier": "3.5.3",
1818
"simple-git-hooks": "2.11.1",
1919
"syncpack": "13.0.4",

packages/creator-hub/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"@types/segment-analytics": "0.0.38",
4747
"@types/semver": "7.5.8",
4848
"@vitejs/plugin-react": "4.3.1",
49+
"@vitest/coverage-v8": "4.0.8",
4950
"ansi-to-html": "0.7.2",
5051
"classnames": "2.5.1",
5152
"cross-env": "7.0.3",
@@ -77,7 +78,7 @@
7778
"test": "npm run test:unit",
7879
"test:e2e": "cross-env E2E='true' playwright test",
7980
"test:main": "vitest run -r main --passWithNoTests",
80-
"test:preload": "vitest run -r preload --passWithNoTests",
81+
"test:preload": "vitest run -r preload --passWithNoTests --coverage",
8182
"test:renderer": "vitest run -r renderer --passWithNoTests",
8283
"test:shared": "vitest run -r shared --passWithNoTests",
8384
"test:unit": "npm run test:main && npm run test:preload && npm run test:renderer && npm run test:shared",

packages/creator-hub/preload/src/modules/workspace.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
import { PACKAGES_LIST } from '/shared/types/pkg';
1111
import { DEFAULT_DEPENDENCY_UPDATE_STRATEGY } from '/shared/types/settings';
1212
import type { GetProjectsOpts, Template, Workspace } from '/shared/types/workspace';
13-
import { FileSystemStorage } from '/shared/types/storage';
1413

1514
import type { Services } from '../services';
1615

@@ -21,7 +20,7 @@ import { DEFAULT_THUMBNAIL, NEW_SCENE_NAME, EMPTY_SCENE_TEMPLATE_REPO } from './
2120
import { getProjectId } from './analytics';
2221

2322
export function initializeWorkspace(services: Services) {
24-
const { config, fs, ipc, path, pkg, npm } = services;
23+
const { config, fs, ipc, path, pkg, npm, project } = services;
2524

2625
// IMPORTANT: when './scene' get's moved to this same factory pattern, we should remove
2726
// the import for { getScene } and use it as "const scene = initializeScene(services)".
@@ -60,7 +59,7 @@ export function initializeWorkspace(services: Services) {
6059
}
6160

6261
async function getOldProjectThumbnailPath(_path: string) {
63-
const workspaceConfigPath = await getConfigPath(_path);
62+
const workspaceConfigPath = await config.getWorkspaceConfigPath(_path);
6463
return path.join(workspaceConfigPath, 'images', 'project-thumbnail.png');
6564
}
6665

@@ -110,7 +109,7 @@ export function initializeWorkspace(services: Services) {
110109
getScene(_path),
111110
fs.stat(_path),
112111
opts?.omitOutdatedPackages ? Promise.resolve({}) : getOutdatedPackages(_path),
113-
getProjectInfoFs(_path),
112+
project.getProjectInfoFs(_path),
114113
]);
115114
const thumbnail = await getProjectThumbnailAsBase64(_path, scene);
116115
const layout = getRowsAndCols(scene.scene.parcels.map($ => parseCoords($)));
@@ -456,19 +455,8 @@ export function initializeWorkspace(services: Services) {
456455
if (error) throw new Error(error);
457456
}
458457

459-
async function getConfigPath(_path: string) {
460-
return ipc.invoke('electron.getWorkspaceConfigPath', _path);
461-
}
462-
463-
async function getProjectInfoFs(_path: string) {
464-
const configPath = await getConfigPath(_path);
465-
const projectInfoPath = path.join(configPath, 'project.json');
466-
const projectInfo = await FileSystemStorage.getOrCreate<ProjectInfo>(projectInfoPath);
467-
return projectInfo;
468-
}
469-
470458
async function updateProjectInfo({ path, info }: { path: string; info: Partial<ProjectInfo> }) {
471-
const projectInfoFs = await getProjectInfoFs(path);
459+
const projectInfoFs = await project.getProjectInfoFs(path);
472460
const projectInfo = await projectInfoFs.getAll();
473461
await projectInfoFs.setAll({ ...projectInfo, ...info });
474462
}
@@ -479,6 +467,8 @@ export function initializeWorkspace(services: Services) {
479467
hasNodeModules,
480468
getProjectThumbnailAsBase64,
481469
getOutdatedPackages,
470+
getProjectThumbnailPath,
471+
getOldProjectThumbnailPath,
482472
getProject,
483473
getPath,
484474
getProjects,
@@ -492,9 +482,7 @@ export function initializeWorkspace(services: Services) {
492482
reimportProject,
493483
saveThumbnail,
494484
openFolder,
495-
getConfigPath,
496485
validateScenesPath,
497-
getProjectInfoFs,
498486
updateProjectInfo,
499487
importProject,
500488
isProjectPathAvailable,

packages/creator-hub/preload/src/services/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,13 @@ export async function setConfig(drafter: (c: WritableDraft<Config>) => void): Pr
1414
});
1515
await invoke('config.writeConfig', update);
1616
}
17+
18+
/**
19+
* Retrieves the configuration path for a given workspace path.
20+
*
21+
* @param {string} path - The path to the workspace.
22+
* @returns {Promise<string>} A promise that resolves to the configuration path.
23+
*/
24+
export async function getWorkspaceConfigPath(path: string) {
25+
return invoke('electron.getWorkspaceConfigPath', path);
26+
}

packages/creator-hub/preload/src/services/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as fs from './fs';
55
import * as npm from './npm';
66
import * as ipc from './ipc';
77
import * as pkg from './pkg';
8+
import * as project from './project';
89

910
export type Services = {
1011
config: typeof config;
@@ -13,6 +14,7 @@ export type Services = {
1314
ipc: typeof ipc;
1415
path: typeof path;
1516
pkg: typeof pkg;
17+
project: typeof project;
1618
};
1719

1820
export const getServices = (): Services => ({
@@ -22,4 +24,5 @@ export const getServices = (): Services => ({
2224
ipc,
2325
path,
2426
pkg,
27+
project,
2528
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import path from 'path';
2+
3+
import { FileSystemStorage } from '/shared/types/storage';
4+
import type { ProjectInfo } from '/shared/types/projects';
5+
import { getWorkspaceConfigPath } from './config';
6+
7+
export async function getProjectInfoFs(_path: string) {
8+
const configPath = await getWorkspaceConfigPath(_path);
9+
const projectInfoPath = path.join(configPath, 'project.json');
10+
const projectInfo = await FileSystemStorage.getOrCreate<ProjectInfo>(projectInfoPath);
11+
return projectInfo;
12+
}
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
1+
import path from 'node:path';
12
import { vi, type Mock } from 'vitest';
23

34
import type { Services } from '../../src/services';
45

56
type DeepMock<T> = {
6-
[key in keyof T]: T[key] extends (...args: any[]) => any
7-
? Mock<Parameters<T[key]>, ReturnType<T[key]>>
8-
: DeepMock<T[key]>;
7+
[K in keyof T]: T[K] extends (...args: any[]) => any ? Mock : DeepMock<T[K]>;
98
};
109

1110
export const getMockServices = (): DeepMock<Services> => ({
1211
config: {
13-
getConfigPath: vi.fn(),
1412
getConfig: vi.fn(),
15-
writeConfig: vi.fn(),
1613
setConfig: vi.fn(),
14+
getWorkspaceConfigPath: vi.fn(),
1715
},
1816
fs: {
1917
stat: vi.fn(),
@@ -26,20 +24,29 @@ export const getMockServices = (): DeepMock<Services> => ({
2624
readdir: vi.fn(),
2725
isDirectory: vi.fn(),
2826
cp: vi.fn(),
27+
isWritable: vi.fn(),
28+
rmdir: vi.fn(),
29+
openPath: vi.fn(),
2930
},
3031
ipc: {
3132
invoke: vi.fn(),
3233
},
3334
path: {
34-
join: vi.fn((...args) => args.join('/')),
35+
join: vi.fn((...args) => path.posix.join(...args)),
36+
basename: vi.fn((arg: string) => path.posix.basename(arg)),
37+
normalize: vi.fn((arg: string) => path.posix.normalize(arg)),
3538
} as any, // temp until we have a "path" service...
3639
npm: {
3740
install: vi.fn(),
3841
getOutdatedDeps: vi.fn(),
42+
getContextFiles: vi.fn(),
3943
},
4044
pkg: {
4145
getPackageJson: vi.fn(),
4246
getPackageVersion: vi.fn(),
4347
hasDependency: vi.fn(),
4448
},
49+
project: {
50+
getProjectInfoFs: vi.fn(),
51+
},
4552
});

0 commit comments

Comments
 (0)