diff --git a/api/__tests__/fileMapper.ts b/api/__tests__/fileMapper.ts
new file mode 100644
index 00000000..f36dcc4c
--- /dev/null
+++ b/api/__tests__/fileMapper.ts
@@ -0,0 +1,23 @@
+import fileStreamResponse from './fixtures/fileStreamResponse.json';
+import { createFileMapperNodeFromStreamResponse } from '../fileMapper';
+
+describe('api/fileMapper', () => {
+ describe('createFileMapperNodeFromStreamResponse()', () => {
+ const src = '1234/test.html';
+ it('should return request#tranform to create a FileMapperNode from the octet-stream response', () => {
+ const node = createFileMapperNodeFromStreamResponse(
+ src,
+ fileStreamResponse
+ );
+ expect(node).toEqual({
+ source: null,
+ path: '/1234/test.html',
+ createdAt: 0,
+ updatedAt: 1565214001268,
+ name: 'test.html',
+ folder: false,
+ children: [],
+ });
+ });
+ });
+});
diff --git a/api/__tests__/fixtures/fileStreamResponse.json b/api/__tests__/fixtures/fileStreamResponse.json
new file mode 100644
index 00000000..51ba5e11
--- /dev/null
+++ b/api/__tests__/fixtures/fileStreamResponse.json
@@ -0,0 +1,17 @@
+{
+ "status": 200,
+ "data": "\n
\n\thello new stuff\n\thello new stuff\n\thello new stuff\n
\n",
+ "headers": {
+ "content-type": "application/octet-stream",
+ "content-length": "132",
+ "content-disposition": "form-data; name=\"file\"; filename=\"test.html\"; creation-date=\"0\"; modification-date=\"1565214001268\""
+ },
+ "request": {
+ "method": "GET",
+ "headers": {
+ "content-type": "application/octet-stream",
+ "accept": "application/octet-stream"
+ }
+ },
+ "statusText": "OK"
+}
diff --git a/api/fileMapper.ts b/api/fileMapper.ts
index 6b5f3900..786cd463 100644
--- a/api/fileMapper.ts
+++ b/api/fileMapper.ts
@@ -8,9 +8,9 @@ import { FileMapperNode, FileMapperOptions, FileTree } from '../types/Files';
export const FILE_MAPPER_API_PATH = 'content/filemapper/v1';
-function createFileMapperNodeFromStreamResponse(
+export function createFileMapperNodeFromStreamResponse(
filePath: string,
- response: AxiosResponse
+ response: Partial
): FileMapperNode {
if (filePath[0] !== '/') {
filePath = `/${filePath}`;
@@ -68,7 +68,7 @@ export async function fetchModule(
});
}
-//Fetch a file by file path.
+// Fetch a file by file path.
export async function fetchFileStream(
accountId: number,
filePath: string,
diff --git a/config/__tests__/CLIConfiguration.ts b/config/__tests__/CLIConfiguration.ts
index f62e3a5c..54f8d957 100644
--- a/config/__tests__/CLIConfiguration.ts
+++ b/config/__tests__/CLIConfiguration.ts
@@ -2,7 +2,7 @@ import config from '../CLIConfiguration';
// TODO write tests for CLIConfiguration.ts
describe('config/CLIConfiguration', () => {
- describe('constructor', () => {
+ describe('constructor()', () => {
it('initializes correctly', () => {
expect(config).toBeDefined();
expect(config.options).toBeDefined();
diff --git a/config/__tests__/config.ts b/config/__tests__/config.ts
index 1e8e4aee..0c3a9f64 100644
--- a/config/__tests__/config.ts
+++ b/config/__tests__/config.ts
@@ -100,8 +100,8 @@ function getAccountByAuthType(
return getAccounts(config).filter(portal => portal.authType === authType)[0];
}
-describe('lib/config', () => {
- describe('setConfig method', () => {
+describe('config/config', () => {
+ describe('setConfig()', () => {
beforeEach(() => {
setConfig(CONFIG);
});
@@ -111,7 +111,7 @@ describe('lib/config', () => {
});
});
- describe('getAccountId method', () => {
+ describe('getAccountId()', () => {
beforeEach(() => {
process.env = {};
setConfig({
@@ -159,7 +159,7 @@ describe('lib/config', () => {
});
});
- describe('updateDefaultAccount method', () => {
+ describe('updateDefaultAccount()', () => {
const myPortalName = 'Foo';
beforeEach(() => {
@@ -172,7 +172,7 @@ describe('lib/config', () => {
});
});
- describe('deleteEmptyConfigFile method', () => {
+ describe('deleteEmptyConfigFile()', () => {
it('does not delete config file if there are contents', () => {
jest
.spyOn(fs, 'readFileSync')
@@ -194,7 +194,7 @@ describe('lib/config', () => {
});
});
- describe('updateAccountConfig method', () => {
+ describe('updateAccountConfig()', () => {
const CONFIG = {
defaultPortal: PORTALS[0].name,
portals: PORTALS,
@@ -342,7 +342,7 @@ describe('lib/config', () => {
});
});
- describe('validateConfig method', () => {
+ describe('validateConfig()', () => {
const DEFAULT_PORTAL = PORTALS[0].name;
it('allows valid config', () => {
@@ -406,7 +406,7 @@ describe('lib/config', () => {
});
});
- describe('getAndLoadConfigIfNeeded method', () => {
+ describe('getAndLoadConfigIfNeeded()', () => {
beforeEach(() => {
setConfig(undefined);
process.env = {};
@@ -551,7 +551,7 @@ describe('lib/config', () => {
});
});
- describe('getConfigPath method', () => {
+ describe('getConfigPath()', () => {
beforeAll(() => {
setConfigPath(CONFIG_PATHS.default);
});
@@ -610,7 +610,7 @@ describe('lib/config', () => {
});
});
- describe('createEmptyConfigFile method', () => {
+ describe('createEmptyConfigFile()', () => {
describe('when no config is present', () => {
let fsExistsSyncSpy: jest.SpyInstance;
diff --git a/config/__tests__/configFile.ts b/config/__tests__/configFile.ts
index 708cc615..32e6f67b 100644
--- a/config/__tests__/configFile.ts
+++ b/config/__tests__/configFile.ts
@@ -34,7 +34,7 @@ const CONFIG = {
} as CLIConfig_NEW;
describe('config/configFile', () => {
- describe('getConfigFilePath method', () => {
+ describe('getConfigFilePath()', () => {
it('returns the config file path', () => {
const configFilePath = getConfigFilePath();
const homeDir = os.homedir();
@@ -51,7 +51,7 @@ describe('config/configFile', () => {
});
});
- describe('configFileExists method', () => {
+ describe('configFileExists()', () => {
it('returns true if config file exists', () => {
existsSyncSpy.mockImplementation(() => true);
const exists = configFileExists();
@@ -61,7 +61,7 @@ describe('config/configFile', () => {
});
});
- describe('configFileIsBlank method', () => {
+ describe('configFileIsBlank()', () => {
it('returns true if config file is blank', () => {
readFileSyncSpy.mockImplementation(() => Buffer.from(''));
const isBlank = configFileIsBlank();
@@ -78,7 +78,7 @@ describe('config/configFile', () => {
});
});
- describe('deleteConfigFile method', () => {
+ describe('deleteConfigFile()', () => {
it('deletes a file', () => {
unlinkSyncSpy.mockImplementation(() => null);
deleteConfigFile();
@@ -87,7 +87,7 @@ describe('config/configFile', () => {
});
});
- describe('readConfigFile method', () => {
+ describe('readConfigFile()', () => {
it('reads the config file', () => {
readFileSyncSpy.mockImplementation(() => Buffer.from('content'));
const result = readConfigFile('path/to/config/file');
@@ -103,7 +103,7 @@ describe('config/configFile', () => {
});
});
- describe('parseConfig method', () => {
+ describe('parseConfig()', () => {
it('parses the config file', () => {
loadSpy.mockImplementation(() => ({}));
const result = parseConfig('config-source');
@@ -119,7 +119,7 @@ describe('config/configFile', () => {
});
});
- describe('loadConfigFromFile method', () => {
+ describe('loadConfigFromFile()', () => {
it('loads the config from file', () => {
readFileSyncSpy.mockImplementation(() => Buffer.from('content'));
loadSpy.mockImplementation(() => ({}));
@@ -136,7 +136,7 @@ describe('config/configFile', () => {
});
});
- describe('writeConfigToFile method', () => {
+ describe('writeConfigToFile()', () => {
it('writes the config to a file', () => {
ensureFileSyncSpy.mockImplementation(() => null);
writeFileSyncSpy.mockImplementation(() => null);
diff --git a/config/__tests__/configUtils.ts b/config/__tests__/configUtils.ts
index 2f2be23b..bbd6df57 100644
--- a/config/__tests__/configUtils.ts
+++ b/config/__tests__/configUtils.ts
@@ -53,7 +53,7 @@ const CONFIG: CLIConfig = {
};
describe('config/configUtils', () => {
- describe('getOrderedAccount method', () => {
+ describe('getOrderedAccount()', () => {
it('returns an ordered account', () => {
const orderedAccount = getOrderedAccount(PAK_ACCOUNT);
const keys = Object.keys(orderedAccount);
@@ -63,7 +63,7 @@ describe('config/configUtils', () => {
});
});
- describe('getOrderedConfig method', () => {
+ describe('getOrderedConfig()', () => {
it('returns an ordered config', () => {
const orderedConfig = getOrderedConfig(CONFIG);
const keys = Object.keys(orderedConfig);
@@ -80,7 +80,7 @@ describe('config/configUtils', () => {
});
});
- describe('generateConfig method', () => {
+ describe('generateConfig()', () => {
it('returns a personal access key auth account', () => {
const pakConfig = generateConfig('personalaccesskey', {
accountId: 111,
diff --git a/config/__tests__/environment.ts b/config/__tests__/environment.ts
index 577841e3..9f42ad67 100644
--- a/config/__tests__/environment.ts
+++ b/config/__tests__/environment.ts
@@ -3,7 +3,7 @@ import { ENVIRONMENTS } from '../../constants/environments';
// TODO write tests for environment.ts
describe('config/environment', () => {
- describe('getValidEnv method', () => {
+ describe('getValidEnv()', () => {
it('defaults to prod when no args are passed', () => {
const env = getValidEnv();
diff --git a/errors/__tests__/apiErrors.ts b/errors/__tests__/apiErrors.ts
index 9121d8ac..df41d3a5 100644
--- a/errors/__tests__/apiErrors.ts
+++ b/errors/__tests__/apiErrors.ts
@@ -38,8 +38,8 @@ export const newStatutsCodeError = (overrides = {}): GenericError => {
};
};
-describe('apiErrors', () => {
- describe('isApiStatusCodeError', () => {
+describe('errors/apiErrors', () => {
+ describe('isApiStatusCodeError()', () => {
it('returns true for api status code errors', () => {
const error1 = newError({ status: 100 });
const error2 = newError({ status: 599 });
@@ -57,7 +57,7 @@ describe('apiErrors', () => {
});
});
- describe('isMissingScopeError', () => {
+ describe('isMissingScopeError()', () => {
it('returns true for missing scope errors', () => {
const error1 = newStatutsCodeError({
status: 403,
@@ -77,7 +77,7 @@ describe('apiErrors', () => {
});
});
- describe('isGatingError', () => {
+ describe('isGatingError()', () => {
it('returns true for gating errors', () => {
const error1 = newStatutsCodeError({
status: 403,
@@ -97,7 +97,7 @@ describe('apiErrors', () => {
});
});
- describe('isApiUploadValidationError', () => {
+ describe('isApiUploadValidationError()', () => {
it('returns true for api upload validation errors', () => {
const error1 = newStatutsCodeError({
status: 400,
@@ -122,7 +122,7 @@ describe('apiErrors', () => {
});
});
- describe('isSpecifiedHubSpotAuthError', () => {
+ describe('isSpecifiedHubSpotAuthError()', () => {
it('returns true for matching HubSpot auth errors', () => {
const error1 = newError({ name: 'HubSpotAuthError', status: 123 });
expect(isSpecifiedHubSpotAuthError(error1, { status: 123 })).toBe(true);
@@ -134,28 +134,28 @@ describe('apiErrors', () => {
});
});
- describe('throwStatusCodeError', () => {
+ describe('throwStatusCodeError()', () => {
it('throws status code error', () => {
const error = newStatutsCodeError() as StatusCodeError;
expect(() => throwStatusCodeError(error)).toThrow();
});
});
- describe('throwApiStatusCodeError', () => {
+ describe('throwApiStatusCodeError()', () => {
it('throws api status code error', () => {
const error = newStatutsCodeError() as StatusCodeError;
expect(() => throwApiStatusCodeError(error)).toThrow();
});
});
- describe('throwApiError', () => {
+ describe('throwApiError()', () => {
it('throws api error', () => {
const error = newStatutsCodeError() as StatusCodeError;
expect(() => throwApiError(error)).toThrow();
});
});
- describe('throwApiUploadError', () => {
+ describe('throwApiUploadError()', () => {
it('throws api upload error', () => {
const error = newStatutsCodeError() as StatusCodeError;
expect(() => throwApiUploadError(error)).toThrow();
diff --git a/errors/__tests__/standardErrors.ts b/errors/__tests__/standardErrors.ts
index e18852d0..1b0e5e7c 100644
--- a/errors/__tests__/standardErrors.ts
+++ b/errors/__tests__/standardErrors.ts
@@ -21,8 +21,8 @@ export const newError = (overrides = {}): BaseError => {
};
};
-describe('standardErrors', () => {
- describe('isSystemError', () => {
+describe('errors/standardErrors', () => {
+ describe('isSystemError()', () => {
it('returns true for system errors', () => {
const error = newError();
expect(isSystemError(error)).toBe(true);
@@ -38,7 +38,7 @@ describe('standardErrors', () => {
});
});
- describe('isFatalError', () => {
+ describe('isFatalError()', () => {
it('returns true for fatal errors', () => {
const cause = newError() as StatusCodeError;
const error = new HubSpotAuthError('A fatal auth error', { cause });
@@ -51,28 +51,28 @@ describe('standardErrors', () => {
});
});
- describe('throwErrorWithMessage', () => {
+ describe('throwErrorWithMessage()', () => {
it('throws error with message', () => {
const error = newError();
expect(() => throwErrorWithMessage('', {}, error)).toThrow();
});
});
- describe('throwTypeErrorWithMessage', () => {
+ describe('throwTypeErrorWithMessage()', () => {
it('throws type error with message', () => {
const error = newError();
expect(() => throwTypeErrorWithMessage('', {}, error)).toThrow();
});
});
- describe('throwAuthErrorWithMessage', () => {
+ describe('throwAuthErrorWithMessage()', () => {
it('throws auth error with message', () => {
const error = newError() as StatusCodeError;
expect(() => throwAuthErrorWithMessage('', {}, error)).toThrow();
});
});
- describe('throwError', () => {
+ describe('throwError()', () => {
it('throws error', () => {
const error = newError();
expect(() => throwError(error)).toThrow();
diff --git a/http/__tests__/getAxiosConfig.ts b/http/__tests__/getAxiosConfig.ts
index 1e8cd50d..f3cbc1f1 100644
--- a/http/__tests__/getAxiosConfig.ts
+++ b/http/__tests__/getAxiosConfig.ts
@@ -11,7 +11,7 @@ const getAndLoadConfigIfNeeded =
const url = 'https://app.hubspot.com';
-describe('getAxiosConfig', () => {
+describe('http/getAxiosConfig', () => {
it('constructs baseURL as expected based on environment', () => {
getAndLoadConfigIfNeeded.mockReturnValue({
accounts: [],
diff --git a/http/__tests__/index.ts b/http/__tests__/index.ts
index 5e41bfb6..b84adf42 100644
--- a/http/__tests__/index.ts
+++ b/http/__tests__/index.ts
@@ -33,7 +33,7 @@ fs.createWriteStream = jest.fn().mockReturnValue({
}),
});
-describe('http', () => {
+describe('http/index', () => {
afterEach(() => {
jest.clearAllMocks();
getAndLoadConfigIfNeeded.mockReset();
diff --git a/lib/__tests__/fileMapper.ts b/lib/__tests__/fileMapper.ts
index 07d99401..b0b6adf3 100644
--- a/lib/__tests__/fileMapper.ts
+++ b/lib/__tests__/fileMapper.ts
@@ -69,7 +69,7 @@ function testPathDeterminationFunction(
});
}
-describe('fileMapper', () => {
+describe('lib/fileMapper', () => {
testPathDeterminationFunction(
'isPathToFile',
'file',
@@ -92,7 +92,7 @@ describe('fileMapper', () => {
[...filePaths, ...folderPaths, ...modulePaths]
);
- describe('recurseFolder', () => {
+ describe('recurseFolder()', () => {
const totalNodesInTree = 11;
const rootNodePath = '/cms-theme-boilerplate/templates';
@@ -162,7 +162,7 @@ describe('fileMapper', () => {
});
});
- describe('getTypeDataFromPath', () => {
+ describe('getTypeDataFromPath()', () => {
it('should return file flags per the request input', () => {
filePaths.forEach(async p => {
const { isFile, isModule, isFolder, isRoot } = getTypeDataFromPath(p);
@@ -201,62 +201,54 @@ describe('fileMapper', () => {
});
});
- describe('fetchFolderFromApi', () => {
+ describe('fetchFolderFromApi()', () => {
const accountId = 67890;
beforeEach(() => {
download.mockClear();
});
- describe('fetch folder', () => {
+ it('folder: should execute the download client per the request input', async () => {
const src = '1234';
- it('should execute the download client per the request input', async () => {
- await fetchFolderFromApi(accountId, src);
- const queryParams = {
- params: {
- buffer: false,
- environmentId: 1,
- version: undefined,
- },
- };
- expect(download).toHaveBeenCalledWith(accountId, src, queryParams);
- });
+ await fetchFolderFromApi(accountId, src);
+ const queryParams = {
+ params: {
+ buffer: false,
+ environmentId: 1,
+ version: undefined,
+ },
+ };
+ expect(download).toHaveBeenCalledWith(accountId, src, queryParams);
});
-
- describe('fetch module (.module)', () => {
+ it('module: should execute the download client per the request input', async () => {
const src = 'cms-theme-boilerplate/modules/Card section.module';
- it('should execute the download client per the request input', async () => {
- await fetchFolderFromApi(accountId, src);
- const queryParams = {
- params: {
- buffer: false,
- environmentId: 1,
- version: undefined,
- },
- };
- expect(download).toHaveBeenCalledWith(accountId, src, queryParams);
- });
+ await fetchFolderFromApi(accountId, src);
+ const queryParams = {
+ params: {
+ buffer: false,
+ environmentId: 1,
+ version: undefined,
+ },
+ };
+ expect(download).toHaveBeenCalledWith(accountId, src, queryParams);
});
-
- describe('fetch all (/)', () => {
+ it('fetch all: should execute the download client per the request input', async () => {
const src = '/';
- it('should execute the download client per the request input', async () => {
- await fetchFolderFromApi(accountId, src);
- const queryParams = {
- params: {
- buffer: false,
- environmentId: 1,
- version: undefined,
- },
- };
- expect(download).toHaveBeenCalledWith(accountId, '@root', queryParams);
- });
+ await fetchFolderFromApi(accountId, src);
+ const queryParams = {
+ params: {
+ buffer: false,
+ environmentId: 1,
+ version: undefined,
+ },
+ };
+ expect(download).toHaveBeenCalledWith(accountId, '@root', queryParams);
});
});
- describe('downloadFileOrFolder', () => {
+ describe('downloadFileOrFolder()', () => {
const accountId = 67890;
beforeEach(() => {
diff --git a/lib/__tests__/fs.ts b/lib/__tests__/fs.ts
index bc09a313..abb810cd 100644
--- a/lib/__tests__/fs.ts
+++ b/lib/__tests__/fs.ts
@@ -22,7 +22,7 @@ function buildLstatMock(opts: {
};
}
-describe('read', () => {
+describe('lib/fs', () => {
describe('getFileInfoAsync()', () => {
it('returns filepath and type for files', async () => {
(fs.lstat as unknown as jest.Mock).mockImplementation(
diff --git a/lib/__tests__/handleFieldsJS.ts b/lib/__tests__/handleFieldsJS.ts
index c5f3ef69..532efb61 100644
--- a/lib/__tests__/handleFieldsJS.ts
+++ b/lib/__tests__/handleFieldsJS.ts
@@ -5,8 +5,8 @@ import child_process from 'child_process';
jest.mock('../fs');
jest.mock('child_process');
-describe('handleFieldsJs', () => {
- describe('FieldsJs', () => {
+describe('lib/cms/handleFieldsJs', () => {
+ describe('FieldsJs()', () => {
beforeEach(() => {
(child_process.fork as jest.Mock).mockImplementation(() => {
return {
diff --git a/lib/__tests__/hubdb.ts b/lib/__tests__/hubdb.ts
index 20beb5f4..3058c933 100644
--- a/lib/__tests__/hubdb.ts
+++ b/lib/__tests__/hubdb.ts
@@ -32,8 +32,8 @@ const publishTable = __publishTable as jest.MockedFunction<
typeof __publishTable
>;
-describe('hubdb', () => {
- describe('downloadHubDbTable', () => {
+describe('lib/hubdb', () => {
+ describe('downloadHubDbTable()', () => {
const accountId = 123;
const tableId = '456';
const destPath = 'tmp.json';
@@ -84,7 +84,7 @@ describe('hubdb', () => {
});
});
- describe('createHubDbTable', () => {
+ describe('createHubDbTable()', () => {
it('creates a table', async () => {
const accountId = 123;
const srcPath = 'tmp.json';
@@ -108,7 +108,7 @@ describe('hubdb', () => {
});
});
- describe('clearHubDbTableRows', () => {
+ describe('clearHubDbTableRows()', () => {
it('clears all of the hubdb table rows', async () => {
fetchRows.mockResolvedValue(hubdbFetchRowResponse);
const result = await clearHubDbTableRows(123, '456');
diff --git a/lib/__tests__/ignoreRules.ts b/lib/__tests__/ignoreRules.ts
index 8cf38c69..11b9d260 100644
--- a/lib/__tests__/ignoreRules.ts
+++ b/lib/__tests__/ignoreRules.ts
@@ -5,8 +5,8 @@ const REPO_FOLDER = `${CWD}/repo-name-here`;
const NODE_MODULES_FOLDER = `${REPO_FOLDER}/node_modules`;
const NODE_MODULES_FILE = `${NODE_MODULES_FOLDER}/a-really-fake-package-name/README.md`;
-describe('ignoreRules', () => {
- describe('shouldIgnoreFile', () => {
+describe('lib/ignoreRules', () => {
+ describe('shouldIgnoreFile()', () => {
it('ignores node_modules folder', () => {
expect(shouldIgnoreFile(NODE_MODULES_FOLDER)).toBe(true);
});
diff --git a/lib/__tests__/modules.ts b/lib/__tests__/modules.ts
index fb992527..132afbff 100644
--- a/lib/__tests__/modules.ts
+++ b/lib/__tests__/modules.ts
@@ -10,7 +10,7 @@ const isHubSpot = true;
// TODO: Replace two missing tests
-describe('modules', () => {
+describe('lib/cms/modules', () => {
describe('validateSrcAndDestPaths()', () => {
const emptyLocal = { isLocal, path: '' };
const emptyHubSpot = { isHubSpot, path: '' };
diff --git a/lib/__tests__/path.ts b/lib/__tests__/path.ts
index df77b1f3..23cf02f7 100644
--- a/lib/__tests__/path.ts
+++ b/lib/__tests__/path.ts
@@ -1,7 +1,7 @@
import path, { PlatformPath } from 'path';
import { splitHubSpotPath, splitLocalPath } from '../path';
-describe('path', () => {
+describe('lib/path', () => {
describe('splitHubSpotPath()', () => {
const testSplit = (
filepath: string,
diff --git a/lib/__tests__/personalAccessKey.ts b/lib/__tests__/personalAccessKey.ts
index 50822944..3a222e64 100644
--- a/lib/__tests__/personalAccessKey.ts
+++ b/lib/__tests__/personalAccessKey.ts
@@ -35,8 +35,8 @@ const fetchSandboxHubData = __fetchSandboxHubData as jest.MockedFunction<
typeof __fetchSandboxHubData
>;
-describe('personalAccessKey', () => {
- describe('accessTokenForPersonalAccessKey', () => {
+describe('lib/personalAccessKey', () => {
+ describe('accessTokenForPersonalAccessKey()', () => {
it('refreshes access token when access token is missing', async () => {
const accountId = 123;
const account = {
@@ -177,7 +177,7 @@ describe('personalAccessKey', () => {
});
});
- describe('updateConfigWithPersonalAccessKey', () => {
+ describe('updateConfigWithPersonalAccessKey()', () => {
beforeEach(() => {
fetchAccessToken.mockClear();
updateAccountConfig.mockClear();
diff --git a/lib/__tests__/templates.ts b/lib/__tests__/templates.ts
new file mode 100644
index 00000000..d7a7cabf
--- /dev/null
+++ b/lib/__tests__/templates.ts
@@ -0,0 +1,77 @@
+import fs from 'fs-extra';
+import {
+ getAnnotationValue,
+ isCodedFile,
+ createTemplate,
+} from '../cms/templates';
+import { downloadGithubRepoContents as __downloadGithubRepoContents } from '../github';
+
+jest.mock('fs-extra');
+jest.mock('../github');
+
+const downloadGithubRepoContents =
+ __downloadGithubRepoContents as jest.MockedFunction<
+ typeof __downloadGithubRepoContents
+ >;
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const makeAnnotation = (options: { [key: string]: any } = {}) => {
+ let result = '\n';
+ return result;
+};
+
+describe('lib/cms/templates', () => {
+ describe('isCodedFile()', () => {
+ it('should return false for invalid input', () => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ expect(isCodedFile(undefined as any)).toBe(false);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ expect(isCodedFile(null as any)).toBe(false);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ expect(isCodedFile(1 as any)).toBe(false);
+ });
+
+ it('should return false for modules', () => {
+ expect(isCodedFile('folder.module/module.html')).toBe(false);
+ });
+
+ it('should return true for templates', () => {
+ expect(isCodedFile('folder/template.html')).toBe(true);
+ });
+ });
+
+ describe('getAnnotationValue()', () => {
+ it('returns the annotation value', () => {
+ const annotations = makeAnnotation({
+ isAvailableForNewContent: 'true',
+ templateType: 'page',
+ });
+
+ const value = getAnnotationValue(annotations, 'templateType');
+ expect(value).toEqual('page');
+ });
+ });
+
+ describe('createTemplate()', () => {
+ beforeEach(() => {
+ downloadGithubRepoContents.mockClear();
+ });
+
+ it('downloads a template from the HubSpot/cms-sample-assets repo', async () => {
+ jest.spyOn(fs, 'mkdirp').mockReturnValue();
+ jest.spyOn(fs, 'existsSync').mockReturnValue(false);
+ await createTemplate('my-template', '/', 'page-template');
+
+ expect(downloadGithubRepoContents).toHaveBeenCalledWith(
+ 'HubSpot/cms-sample-assets',
+ 'templates/page-template.html',
+ '/my-template.html'
+ );
+ });
+ });
+});
diff --git a/lib/__tests__/uploadFolder.ts b/lib/__tests__/uploadFolder.ts
index 297e1490..724f4148 100644
--- a/lib/__tests__/uploadFolder.ts
+++ b/lib/__tests__/uploadFolder.ts
@@ -80,7 +80,7 @@ const filesProto = [
'folder/sample.module/module.html',
'folder/templates/page.html',
];
-describe('cms/uploadFolder', () => {
+describe('lib/cms/uploadFolder', () => {
beforeAll(() => {
createIgnoreFilter.mockImplementation(() => () => true);
});
diff --git a/lib/cms/templates.ts b/lib/cms/templates.ts
index c229427a..92b3e55e 100644
--- a/lib/cms/templates.ts
+++ b/lib/cms/templates.ts
@@ -1,6 +1,6 @@
import fs from 'fs-extra';
import path from 'path';
-import { downloadGithubRepoContents } from '../../lib/github';
+import { downloadGithubRepoContents } from '../github';
import { throwErrorWithMessage } from '../../errors/standardErrors';
import { debug, makeTypedLogger } from '../../utils/logger';
import { LogCallbacksArg } from '../../types/LogCallbacks';
diff --git a/utils/__tests__/fieldsJS.ts b/utils/__tests__/fieldsJS.ts
index 4f817040..02d7ca50 100644
--- a/utils/__tests__/fieldsJS.ts
+++ b/utils/__tests__/fieldsJS.ts
@@ -1,6 +1,6 @@
import { fieldsArrayToJson } from '../cms/fieldsJS';
-describe('fieldsJS', () => {
+describe('utils/cms/fieldsJS', () => {
describe('fieldsArrayToJson()', () => {
it('flattens nested arrays', async () => {
const input = [
diff --git a/utils/__tests__/git.ts b/utils/__tests__/git.ts
index 628df7f5..2c54e835 100644
--- a/utils/__tests__/git.ts
+++ b/utils/__tests__/git.ts
@@ -1,8 +1,8 @@
import { configFilenameIsIgnoredByGitignore } from '../../utils/git';
import fs from 'fs-extra';
-describe('lib/git', () => {
- describe('configFilenameIsIgnoredByGitignore method', () => {
+describe('utils/cms/git', () => {
+ describe('configFilenameIsIgnoredByGitignore()', () => {
it('returns false if the config file is not ignored', () => {
const gitignoreContent = '';
const configPath = `/Users/fakeuser/someproject/hubspot.config.yml`;
diff --git a/utils/__tests__/modules.ts b/utils/__tests__/modules.ts
index 686c13bd..d49dea8f 100644
--- a/utils/__tests__/modules.ts
+++ b/utils/__tests__/modules.ts
@@ -9,7 +9,7 @@ const isHubSpot = true;
// TODO: Replace two missing tests
-describe('cli-lib/modules', () => {
+describe('utils/cms/modules', () => {
describe('isModuleFolder()', () => {
it('should throw on invalid input', () => {
// @ts-expect-error testing invalid input