generator-begcode
Version:
Spring Boot + Angular/React/Vue in one handy generator
306 lines (305 loc) • 13.5 kB
JavaScript
import { YeomanTest, RunContext, result } from 'yeoman-test';
import { merge, set } from 'lodash-es';
import { globSync } from 'glob';
import { basename, dirname, join } from 'path';
import { fileURLToPath } from 'url';
import EnvironmentBuilder from '../cli/environment-builder.mjs';
import { JHIPSTER_CONFIG_DIR } from '../generators/generator-constants.js';
import { GENERATOR_WORKSPACES } from '../generators/generator-list.js';
import getGenerator from './get-generator.js';
import { createJHipsterLogger, normalizePathEnd, parseCreationTimestamp } from '../generators/base/support/index.js';
import BaseGenerator from '../generators/base/index.js';
import { getPackageRoot, isDistFolder } from '../lib/index.js';
const runResult = result;
export { runResult, runResult as result };
const DEFAULT_TEST_SETTINGS = { forwardCwd: true };
const DEFAULT_TEST_OPTIONS = { skipInstall: true };
const DEFAULT_TEST_ENV_OPTIONS = { skipInstall: true, dryRun: false };
const generatorsDir = join(fileURLToPath(import.meta.url), '../../generators');
const mockedGenerators = [
...globSync('*/index.{j,t}s', { cwd: generatorsDir, posix: true }).map(file => dirname(file)),
...globSync('*/generators/*/index.{j,t}s', { cwd: generatorsDir, posix: true }).map(file => dirname(file).replace('/generators/', ':')),
]
.filter(gen => !gen.startsWith('bootstrap-'))
.map(gen => `begcode:${gen}`)
.sort();
const defaultSharedApplication = Object.fromEntries(['CLIENT_WEBPACK_DIR'].map(key => [key, undefined]));
let defaultMockFactory;
export const defineDefaults = async ({ mockFactory } = {}) => {
if (mockFactory) {
defaultMockFactory = mockFactory;
}
else if (!defaultMockFactory) {
try {
const { esmocha } = await import('esmocha');
defaultMockFactory = esmocha.fn;
}
catch {
throw new Error('loadMockFactory should be called before using mock');
}
}
};
const createFiles = (workspaceFolder, configuration, entities) => {
if (!configuration.baseName) {
throw new Error('baseName is required');
}
workspaceFolder = workspaceFolder ? normalizePathEnd(workspaceFolder) : workspaceFolder;
const entityFiles = entities
? Object.fromEntries(entities?.map(entity => [`${workspaceFolder}${JHIPSTER_CONFIG_DIR}/${entity.name}.json`, entity]))
: {};
configuration = { entities: entities?.map(e => e.name), ...configuration };
return {
[`${workspaceFolder}.yo-rc.json`]: { 'generator-jhipster': configuration },
...entityFiles,
};
};
export const createJHipsterConfigFiles = (configuration, entities) => createFiles('', configuration, entities);
export const createBlueprintFiles = (blueprintPackage, { packageJson, generator = 'test-blueprint', generatorContent, files = {} } = {}) => {
generatorContent =
generatorContent ??
`export const createGenerator = async env => {
const BaseGenerator = await env.requireGenerator('begcode:base');
return class extends BaseGenerator {
get [BaseGenerator.INITIALIZING]() {
return {};
}
};
};
`;
const generators = Array.isArray(generator) ? generator : [generator];
return {
[`node_modules/${blueprintPackage}/package.json`]: {
name: blueprintPackage,
version: '9.9.9',
type: 'module',
...packageJson,
},
...Object.fromEntries(generators.map(generator => [`node_modules/${blueprintPackage}/generators/${generator}/index.js`, generatorContent])),
...Object.fromEntries(Object.entries(files).map(([file, content]) => [`node_modules/${blueprintPackage}/${file}`, content])),
};
};
class JHipsterRunContext extends RunContext {
sharedSource;
sharedData;
sharedApplication;
sharedControl;
workspaceApplications = [];
commonWorkspacesConfig;
generateApplicationsSet = false;
withOptions(options) {
return super.withOptions(options);
}
withJHipsterConfig(configuration, entities) {
return this.withFiles(createFiles('', { baseName: 'jhipster', creationTimestamp: parseCreationTimestamp('2020-01-01'), ...configuration }, entities));
}
withSkipWritingPriorities() {
return this.withOptions({ skipPriorities: ['writing', 'postWriting', 'writingEntities', 'postWritingEntities'] });
}
withWorkspacesCommonConfig(commonWorkspacesConfig) {
if (this.workspaceApplications.length > 0) {
throw new Error('Cannot be called after withWorkspaceApplication');
}
this.commonWorkspacesConfig = { ...this.commonWorkspacesConfig, ...commonWorkspacesConfig };
return this;
}
withWorkspaceApplicationAtFolder(workspaceFolder, configuration, entities) {
if (this.generateApplicationsSet) {
throw new Error('Cannot be called after withWorkspaceApplication');
}
this.workspaceApplications.push(workspaceFolder);
return this.withFiles(createFiles(workspaceFolder, { ...configuration, ...this.commonWorkspacesConfig }, entities));
}
withWorkspaceApplication(configuration, entities) {
return this.withWorkspaceApplicationAtFolder(configuration.baseName, configuration, entities);
}
withWorkspacesSamples(...appNames) {
return this.onBeforePrepare(async () => {
try {
const { default: deploymentTestSamples } = await import('./support/deployment-samples.js');
for (const appName of appNames) {
const application = deploymentTestSamples[appName];
if (!application) {
throw new Error(`Application ${appName} not found`);
}
this.withWorkspaceApplicationAtFolder(appName, deploymentTestSamples[appName]);
}
}
catch {
throw new Error('Samples are currently not available to blueprint testing.');
}
});
}
withGenerateWorkspaceApplications(generateWorkspaces = false) {
return this.onBeforePrepare(() => {
this.generateApplicationsSet = true;
this.withOptions({ generateApplications: true, workspacesFolders: this.workspaceApplications, workspaces: generateWorkspaces });
});
}
withJHipsterLookup() {
return this.withLookups([{ packagePaths: [getPackageRoot()], lookups: [`${isDistFolder() ? 'dist/' : ''}generators`] }]);
}
withParentBlueprintLookup(lookups = ['generators']) {
const packageRootParent = join(getPackageRoot(), '..');
if (basename(packageRootParent) === 'node_modules') {
this.withLookups([{ packagePaths: [join(packageRootParent, '..')], lookups }]);
}
else {
this.withLookups([{ packagePaths: [process.cwd()], lookups }]);
}
return this;
}
withFakeTestBlueprint(blueprintPackage, { packageJson, generator = 'test-blueprint' } = {}) {
return this.withFiles(createBlueprintFiles(blueprintPackage, { packageJson, generator }))
.withLookups({ localOnly: true })
.commitFiles();
}
withMockedSource() {
this.sharedSource = new Proxy({}, {
get(target, name) {
if (!target[name]) {
target[name] = defaultMockFactory();
}
return target[name];
},
set() {
return true;
},
});
return this.onBeforePrepare(() => defineDefaults()).withSharedData({ sharedSource: this.sharedSource });
}
withControl(sharedControl) {
this.sharedControl = this.sharedControl ?? {};
Object.assign(this.sharedControl, sharedControl);
return this.withSharedData({ control: this.sharedControl });
}
withSharedApplication(sharedApplication) {
this.sharedApplication = this.sharedApplication ?? { ...defaultSharedApplication };
merge(this.sharedApplication, sharedApplication);
return this.withSharedData({ sharedApplication: this.sharedApplication });
}
withMockedJHipsterGenerators(exceptList = []) {
exceptList = exceptList.map(gen => (gen.startsWith('jhipster:') ? gen : `jhipster:${gen}`));
return this.withMockedGenerators(mockedGenerators.filter(gen => !exceptList.includes(gen) && this.Generator !== gen));
}
withGradleBuildTool() {
return this.withFiles({
'build.gradle': `
dependencies {
// jhipster-needle-gradle-dependency
}
plugins {
// jhipster-needle-gradle-plugins
}
`,
}).withJHipsterConfig({ buildTool: 'gradle' });
}
withSharedData(sharedData) {
if (!this.sharedData) {
const applicationId = 'test-application';
this.sharedData = { ...sharedData };
set(this.envOptions, `sharedOptions.sharedData.applications.${applicationId}`, this.sharedData);
return this.withOptions({
applicationId,
});
}
Object.assign(this.sharedData, sharedData);
return this;
}
async run() {
const runResult = (await super.run());
if (this.sharedSource) {
const sourceCallsArg = Object.fromEntries(Object.entries(this.sharedSource).map(([name, fn]) => [name, fn.mock.calls.map(args => args[0])]));
if (sourceCallsArg.addEntitiesToClient) {
sourceCallsArg.addEntitiesToClient = sourceCallsArg.addEntitiesToClient.map(({ application, entities }) => ({
application: `Application[${application.baseName}]`,
entities: entities.map(entity => `Entity[${entity.name}]`),
}));
}
if (sourceCallsArg.addEntityToCache) {
sourceCallsArg.addEntityToCache = sourceCallsArg.addEntityToCache.map(({ relationships, ...fields }) => ({
...fields,
relationships: relationships.map(rel => `Relationship[${rel.relationshipName}]`),
}));
}
runResult.sourceCallsArg = sourceCallsArg;
}
runResult.composedMockedGenerators = mockedGenerators.filter(gen => runResult.mockedGenerators[gen]?.called && !['begcode:bootstrap', 'begcode:project-name'].includes(gen));
return runResult;
}
}
class JHipsterTest extends YeomanTest {
constructor() {
super();
this.adapterOptions = { log: createJHipsterLogger() };
}
run(GeneratorOrNamespace, settings, envOptions) {
return super.run(GeneratorOrNamespace, settings, envOptions).withAdapterOptions({ log: createJHipsterLogger() });
}
runJHipster(jhipsterGenerator, settings, envOptions) {
return this.run(getGenerator(jhipsterGenerator), settings, envOptions);
}
runTestBlueprintGenerator() {
const blueprintNS = 'begcode:test-blueprint';
class BlueprintedGenerator extends BaseGenerator {
async beforeQueue() {
if (!this.fromBlueprint) {
await this.composeWithBlueprints();
}
}
rootGeneratorName() {
return 'generator-begcode';
}
get [BaseGenerator.INITIALIZING]() {
return {};
}
}
return this.run(blueprintNS).withGenerators([[BlueprintedGenerator, { namespace: blueprintNS }]]);
}
create(GeneratorOrNamespace, settings, envOptions) {
return super.create(GeneratorOrNamespace, settings, envOptions);
}
createJHipster(jhipsterGenerator, settings, envOptions) {
return this.create(getGenerator(jhipsterGenerator), settings, envOptions);
}
generateDeploymentWorkspaces(commonConfig) {
return this.runJHipster(GENERATOR_WORKSPACES)
.withWorkspacesCommonConfig(commonConfig ?? {})
.withOptions({
generateWorkspaces: true,
generateWith: 'docker',
skipPriorities: ['prompting'],
});
}
}
export function createTestHelpers(options = {}) {
const { environmentOptions = {} } = options;
const sharedOptions = {
...DEFAULT_TEST_OPTIONS,
...environmentOptions.sharedOptions,
};
const helper = new JHipsterTest();
helper.settings = { ...DEFAULT_TEST_SETTINGS, ...options.settings };
helper.environmentOptions = { ...DEFAULT_TEST_ENV_OPTIONS, ...environmentOptions, sharedOptions };
helper.generatorOptions = { ...DEFAULT_TEST_OPTIONS, ...options.generatorOptions };
helper.createEnv = (...args) => EnvironmentBuilder.createEnv(...args);
helper.getRunContextType = () => JHipsterRunContext;
return helper;
}
const commonTestOptions = {
reproducible: true,
skipChecks: true,
reproducibleTests: true,
noInsight: true,
useVersionPlaceholders: true,
fakeKeytool: true,
};
export const basicHelpers = createTestHelpers({ generatorOptions: { ...commonTestOptions } });
export const defaultHelpers = createTestHelpers({
generatorOptions: { skipPrettier: true, ...commonTestOptions },
environmentOptions: { dryRun: true },
});
export const skipPrettierHelpers = createTestHelpers({ generatorOptions: { skipPrettier: true, ...commonTestOptions } });
export const dryRunHelpers = createTestHelpers({
generatorOptions: { ...commonTestOptions },
environmentOptions: { dryRun: true },
});