@tywalk/pcf-helper
Version:
Command line helper for building and publishing PCF controls to Dataverse.
173 lines (172 loc) • 8.47 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const configUtil_1 = require("../util/configUtil");
jest.mock('fs');
jest.mock('os');
jest.mock('@tywalk/color-logger', () => ({
__esModule: true,
default: {
log: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
},
}));
const mockFs = fs_1.default;
const mockOs = os_1.default;
/**
* Wires fs.existsSync/readFileSync to a map of path → file contents. Any path
* not in the map behaves as if the file does not exist.
*/
function setFakeFiles(files) {
mockFs.existsSync.mockImplementation((p) => Object.prototype.hasOwnProperty.call(files, p.toString()));
mockFs.readFileSync.mockImplementation((p, _encoding) => {
const key = p.toString();
if (!(key in files))
throw new Error(`ENOENT: ${key}`);
return files[key];
});
}
describe('configUtil', () => {
const HOME = '/home/tester';
const CWD = '/workspace/proj';
beforeEach(() => {
jest.clearAllMocks();
mockOs.homedir.mockReturnValue(HOME);
jest.spyOn(process, 'cwd').mockReturnValue(CWD);
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('path helpers', () => {
it('resolves the global config under the user home directory', () => {
expect((0, configUtil_1.getGlobalConfigPath)()).toBe(path_1.default.join(HOME, '.pcf-helper', 'config.json'));
});
it('resolves the project config at the provided cwd', () => {
expect((0, configUtil_1.getProjectConfigPath)('/some/cwd')).toBe(path_1.default.join('/some/cwd', 'pcf-helper.config.json'));
});
});
describe('loadPcfHelperConfig', () => {
it('returns empty merged config when neither file exists', () => {
setFakeFiles({});
const loaded = (0, configUtil_1.loadPcfHelperConfig)();
expect(loaded.sources).toEqual([]);
expect(loaded.merged.profiles).toEqual({});
expect(loaded.merged.defaultProfile).toBeUndefined();
});
it('loads only from project when global is missing', () => {
var _a, _b;
const projectCfg = {
defaultProfile: 'dev',
profiles: { dev: { environment: 'DevOrg' } },
};
setFakeFiles({
[path_1.default.join(CWD, 'pcf-helper.config.json')]: JSON.stringify(projectCfg),
});
const loaded = (0, configUtil_1.loadPcfHelperConfig)();
expect(loaded.sources).toHaveLength(1);
expect(loaded.merged.defaultProfile).toBe('dev');
expect((_b = (_a = loaded.merged.profiles) === null || _a === void 0 ? void 0 : _a.dev) === null || _b === void 0 ? void 0 : _b.environment).toBe('DevOrg');
});
it('merges profiles by name — project value wins on collision', () => {
var _a, _b, _c, _d;
const globalCfg = {
profiles: {
dev: { environment: 'GlobalDev', publisherName: 'GlobalPub' },
prod: { environment: 'GlobalProd' },
},
};
const projectCfg = {
profiles: {
dev: { environment: 'ProjectDev' }, // overrides
},
};
setFakeFiles({
[path_1.default.join(HOME, '.pcf-helper', 'config.json')]: JSON.stringify(globalCfg),
[path_1.default.join(CWD, 'pcf-helper.config.json')]: JSON.stringify(projectCfg),
});
const loaded = (0, configUtil_1.loadPcfHelperConfig)();
// Project dev beats global dev (whole-object replacement by design)
expect((_b = (_a = loaded.merged.profiles) === null || _a === void 0 ? void 0 : _a.dev) === null || _b === void 0 ? void 0 : _b.environment).toBe('ProjectDev');
// Global-only profile is still present
expect((_d = (_c = loaded.merged.profiles) === null || _c === void 0 ? void 0 : _c.prod) === null || _d === void 0 ? void 0 : _d.environment).toBe('GlobalProd');
});
it('projects defaultProfile wins over global defaultProfile', () => {
setFakeFiles({
[path_1.default.join(HOME, '.pcf-helper', 'config.json')]: JSON.stringify({ defaultProfile: 'a' }),
[path_1.default.join(CWD, 'pcf-helper.config.json')]: JSON.stringify({ defaultProfile: 'b' }),
});
expect((0, configUtil_1.loadPcfHelperConfig)().merged.defaultProfile).toBe('b');
});
it('treats malformed JSON as empty and does not throw', () => {
setFakeFiles({
[path_1.default.join(CWD, 'pcf-helper.config.json')]: 'not json {{{',
});
const loaded = (0, configUtil_1.loadPcfHelperConfig)();
expect(loaded.merged.profiles).toEqual({});
});
it('merges top-level session blocks field-by-field', () => {
var _a, _b;
setFakeFiles({
[path_1.default.join(HOME, '.pcf-helper', 'config.json')]: JSON.stringify({
session: { remoteEnvironmentUrl: 'https://global', startWatch: true },
}),
[path_1.default.join(CWD, 'pcf-helper.config.json')]: JSON.stringify({
session: { remoteEnvironmentUrl: 'https://project' },
}),
});
const loaded = (0, configUtil_1.loadPcfHelperConfig)();
expect((_a = loaded.merged.session) === null || _a === void 0 ? void 0 : _a.remoteEnvironmentUrl).toBe('https://project');
expect((_b = loaded.merged.session) === null || _b === void 0 ? void 0 : _b.startWatch).toBe(true);
});
});
describe('resolveProfile', () => {
const merged = {
defaultProfile: 'dev',
profiles: {
dev: { environment: 'DevOrg' },
prod: { environment: 'ProdOrg' },
},
};
it('returns the requested profile by name', () => {
const { name, profile } = (0, configUtil_1.resolveProfile)('prod', merged);
expect(name).toBe('prod');
expect(profile === null || profile === void 0 ? void 0 : profile.environment).toBe('ProdOrg');
});
it('falls back to defaultProfile when no name is given', () => {
const { name, profile } = (0, configUtil_1.resolveProfile)(undefined, merged);
expect(name).toBe('dev');
expect(profile === null || profile === void 0 ? void 0 : profile.environment).toBe('DevOrg');
});
it('returns an empty result when no name and no default', () => {
const { name, profile } = (0, configUtil_1.resolveProfile)(undefined, { profiles: {} });
expect(name).toBeUndefined();
expect(profile).toBeUndefined();
});
it('throws a helpful error when the named profile is missing', () => {
expect(() => (0, configUtil_1.resolveProfile)('nope', merged)).toThrow(/Profile "nope" not found/);
});
});
describe('mergeSessionConfig', () => {
it('layers later values over earlier values', () => {
const merged = (0, configUtil_1.mergeSessionConfig)({ remoteEnvironmentUrl: 'low', startWatch: false }, { remoteEnvironmentUrl: 'mid' }, { startWatch: true });
expect(merged.remoteEnvironmentUrl).toBe('mid');
expect(merged.startWatch).toBe(true);
});
it('skips undefined layers', () => {
const merged = (0, configUtil_1.mergeSessionConfig)(undefined, { remoteEnvironmentUrl: 'only' }, undefined);
expect(merged.remoteEnvironmentUrl).toBe('only');
});
it('ignores undefined fields in a layer (does not wipe lower values)', () => {
const merged = (0, configUtil_1.mergeSessionConfig)({ remoteEnvironmentUrl: 'keep' }, { remoteEnvironmentUrl: undefined, startWatch: true });
expect(merged.remoteEnvironmentUrl).toBe('keep');
expect(merged.startWatch).toBe(true);
});
});
});