Skip to content

Commit

Permalink
Change test templates to be without TestBed
Browse files Browse the repository at this point in the history
* Add option to use test bed templates for specs
* By default use templates with no test bed for better performance and focus on unit testing functions
* Add a more generic arrayUnionOverride function to use in generator.
* Update readme and contributing
* Update package version and changelog
  • Loading branch information
deniszholob committed Jun 8, 2023
1 parent 5ad14d6 commit 0c895e9
Show file tree
Hide file tree
Showing 16 changed files with 194 additions and 95 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"explorer.autoRevealExclude": {
"**/node_modules": true
},
"material-icon-theme.folders.associations": {
"templates-alt": "template"
},
"files.exclude": {
".husky": true,
".vscode-test": true,
Expand Down
16 changes: 12 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,24 @@

## [Unreleased]

## [0.0.7]
### Added
- New setting to toggle `TestBed` in angular spec tests
### Changed
- Default specs do not have the `TestBed`
- Can toggle `defaultSpecsUseTestBed` setting to revert back to using `TestBed`


## [0.0.6]
### Added
- Error message popup for any errors that were encountered
- Error message popup for any errors that were encountered
### Changed
- If there are extra custom templates that has the known file suffixes (component, service, pipe, etc..), they will be rendered as well.
- If there are extra custom templates that has the known file suffixes (component, service, pipe, etc..), they will be rendered as well.

## [0.0.5]
### Added
- More generator options: Route, Directive, Pipe
- New setting options to toggle specs and stories
- More generator options: Route, Directive, Pipe
- New setting options to toggle specs and stories
### Changed
- Template variable names to be more consistent

Expand Down
16 changes: 16 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
## Dev
* Run `npm i` to install dev npm packages
* Go to the debugger window (Run&Debug icon on side bar)
* Click `Run Extension`
* New window will open where you can test the extension code changes
* A watch task will be automatically spawned to rebuild the extension as code changes
* NOTE: Sometimes the watch task does not pick up the template changes, so you need to run the `npm run template-copy` command

## Commit/Push/Publish
* Commit as much as you like, but squash changes into 1 commit before a new release push
* Make sure to update the following before pushing/publishing
* [package.json](./package.json) version number
* [CHANGELOG](./CHANGELOG.md) version change description
* Tag the commit to be the published release and push
* [CI/CD](.github/workflows/main.yml) will automatically build and publish the extension from main branch

## References
* [Extension Development Quick Start](./vsc-extension-quickstart.md)
* [VsCode First Extension Doc](https://code.visualstudio.com/api/get-started/your-first-extension)
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,13 @@ If you find the extension or the source code useful, consider:
In `.vscode/settings.json` add in the following settings to customize the extension.

* `customTemplateFolder` - Custom template folder location. Path relative you your workspace root. If null will use extension default templates.
* `defaultSpecsUseTestBed` - Toggle using default spec templates with angular TestBed or without it for better performance.
* `generateSpec` - Toggle generation of spec files.
* `generateStories` - Toggle generation of stories files.

```json
"angular-files-generator.customTemplateFolder": ".vscode/ngfg-templates",
"angular-files-generator.defaultSpecsUseTestBed": false,
"angular-files-generator.generateSpec": true,
"angular-files-generator.generateStories": true,
```
Expand All @@ -54,14 +56,15 @@ In `.vscode/settings.json` add in the following settings to customize the extens

## Requirements

Generator creates the files from custom templates, so nothing is needed to create the files.
To use the files install
Generator creates the files from custom templates, so **nothing is needed to create** the files!
However, to use the files install

- [Angular](https://angular.io/docs)
- [Jest](https://jestjs.io/docs/testing-frameworks)
- [Storybook](https://storybook.js.org/docs/angular/get-started/introduction)
- [Angular](https://angular.io/docs) for component code
- [Jest](https://jestjs.io/docs/testing-frameworks) for unit testing
- [Storybook](https://storybook.js.org/docs/angular/get-started/introduction) for visual tests/documentation
- [ng-mocks](https://ng-mocks.sudo.eu/) recommended for helping mock services, etc.. for jest or storybook

## Known Issues
## Known Issues/Feature Requests

https://github.com/deniszholob/angular-files-generator/issues

Expand Down
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"url": "https://github.com/deniszholob/angular-files-generator/issues"
},
"icon": "images/icon-96x96.png",
"version": "0.0.6",
"version": "0.0.7",
"license": "GPL-3",
"engines": {
"node": ">=18.12.1",
Expand Down Expand Up @@ -48,6 +48,11 @@
"default": null,
"description": "Custom template folder location. Path relative you your workspace root. If null will use extension default templates."
},
"angular-files-generator.defaultSpecsUseTestBed": {
"type": "boolean",
"default": false,
"description": "Toggle using default spec templates with angular TestBed or without it for better performance."
},
"angular-files-generator.generateSpec": {
"type": "boolean",
"default": true,
Expand Down Expand Up @@ -146,7 +151,7 @@
"package": "npx vsce package",
"publish": "npx vsce publish",
"remove-output": "rimraf ./out ",
"template-copy": "copyfiles -f ./src/templates/**/*.mustache ./out/templates/",
"template-copy": "copyfiles -f ./src/templates/**/*.mustache ./out/templates/ && copyfiles -f ./src/templates-alt/**/*.mustache ./out/templates-alt/",
"compile": "npm run pre-build && tsc -p ./",
"watch": "npm run pre-build && tsc -watch -p ./",
"pretest": "npm run compile && npm run lint",
Expand Down
21 changes: 21 additions & 0 deletions src/generator/array-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,24 @@ export function arrayDifference<T>(
): T[] {
return arrA.filter((x) => !arrayIncludes(arrB, x, comparator));
}

/**
* If arrA=[{n="bob",a="5"},{n="alice",a="10"}]
* And if arrB=[{n="alice",a="11"},{n="jack",a="20"}]
* And if comparator=(a,b)=>a.n===b.n
* Then return arr=[{n="bob",a="5"},{n="alice",a="11"},{n="jack",a="20"}]
* @return Elements in both arrays, with similar elements in B overriding elements in A
*/
export function arrayUnionOverride<T>(
arrA: T[],
arrB: T[],
comparator: ArrayComparator<T>
): T[] {
// A contains items not in B
const ADiffB: T[] = arrayDifference(arrA, arrB, comparator);
// B contains overrides for A
const BIntersA: T[] = arrayIntersection(arrB, arrA, comparator);
// B contains extra items not in A
const BDiffA: T[] = arrayDifference(arrB, arrA, comparator);
return [...ADiffB, ...BIntersA, ...BDiffA];
}
73 changes: 36 additions & 37 deletions src/generator/generate-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ import { NgFileType } from './angular-file-type.model';
import { log } from './formatter';
import {
getSetting_customTemplateFolder,
getSetting_defaultSpecsUseTestBed,
getSetting_generateSpec,
getSetting_generateStories,
} from './settings';
import {
ArrayComparator,
arrayDifference,
arrayIntersection,
arrayUnionOverride,
} from './array-functions';

export const TEMPLATES_FOLDER = 'templates';
export const TEMPLATES_ALT_FOLDER = 'templates-alt'; // Currently are alt tests using TestBed
export interface GeneratorVariables {
/** Ex: c:/angular-files-generator/out */
extensionSrcDir: string;
Expand All @@ -40,6 +43,9 @@ interface Templates {
templateFiles: string[];
}

const comparatorTemplateFile: ArrayComparator<TemplateFile> = (a, b) =>
a.name === b.name;

/** Main generator function: Gathers template files and converts to angular files via Mustache.js */
export async function generate(
templateVariables: TemplateVariables,
Expand Down Expand Up @@ -69,18 +75,24 @@ export async function generate(
templateVariables
);
}
/** @returns templates from directory */
async function getTemplates(templatesPath: string): Promise<Templates> {
const templateFiles: string[] = await fs.promises.readdir(templatesPath);
return { templatesPath, templateFiles };
// return templateFiles.map((f) => new TemplateFile(f, templatesPath));
}

/** @returns extension's default templates */
async function getExtensionTemplates(
extensionSrcDir: string
extensionSrcDir: string,
templateFolder:
| typeof TEMPLATES_FOLDER
| typeof TEMPLATES_ALT_FOLDER = TEMPLATES_FOLDER
): Promise<Templates> {
log('extensionSrcDir:', extensionSrcDir);
const templatesPath: string = path.join(extensionSrcDir, TEMPLATES_FOLDER);
const templatesPath: string = path.join(extensionSrcDir, templateFolder);
log('templatesPath:', templatesPath);
const templateFiles: string[] = await fs.promises.readdir(templatesPath);
return { templateFiles, templatesPath };

// return templateFiles.map((f) => new TemplateFile(f, templatesPath));
return getTemplates(templatesPath);
}

/** @returns user's custom templates */
Expand All @@ -94,10 +106,9 @@ async function getCustomTemplates(): Promise<Templates | undefined> {
? path.join(workspaceRoot, customTemplatesFolderName)
: undefined;

if (!(templatesPath && fs.existsSync(templatesPath))) return undefined;

const templateFiles: string[] = await fs.promises.readdir(templatesPath);
return { templateFiles, templatesPath };
return templatesPath && fs.existsSync(templatesPath)
? getTemplates(templatesPath)
: undefined;
}

/**
Expand Down Expand Up @@ -130,44 +141,32 @@ function templatesToTemplateFiles(templates: Templates): TemplateFile[] {
async function getRenderTemplates(
extensionSrcDir: string
): Promise<TemplateFile[]> {
const defaultTemplates: Templates = await getExtensionTemplates(
extensionSrcDir
let defaultTemplateFiles: TemplateFile[] = templatesToTemplateFiles(
await getExtensionTemplates(extensionSrcDir, TEMPLATES_FOLDER)
);
const customTemplates: Templates | undefined = await getCustomTemplates();
const defaultTemplateFiles: TemplateFile[] =
templatesToTemplateFiles(defaultTemplates);

if (getSetting_defaultSpecsUseTestBed()) {
defaultTemplateFiles = arrayUnionOverride(
defaultTemplateFiles,
templatesToTemplateFiles(
await getExtensionTemplates(extensionSrcDir, TEMPLATES_ALT_FOLDER)
),
comparatorTemplateFile
);
}

const customTemplates: Templates | undefined = await getCustomTemplates();
if (!customTemplates) return defaultTemplateFiles;

// Override and extra template Logic
const customTemplateFiles: TemplateFile[] =
templatesToTemplateFiles(customTemplates);

const comparator: ArrayComparator<TemplateFile> = (a, b) => a.name === b.name;
// Default Templates that do not have a corresponding user override
const nonOverridableDefaultTemplateFiles: TemplateFile[] = arrayDifference(
return arrayUnionOverride(
defaultTemplateFiles,
customTemplateFiles,
comparator
comparatorTemplateFile
);
// Templates that need to be overridden
const overrideTemplateFiles: TemplateFile[] = arrayIntersection(
customTemplateFiles,
defaultTemplateFiles,
comparator
);
// Custom Templates that do not have a corresponding default template
const extraCustomTemplateFiles: TemplateFile[] = arrayDifference(
customTemplateFiles,
defaultTemplateFiles,
comparator
);

return [
...nonOverridableDefaultTemplateFiles,
...overrideTemplateFiles,
...extraCustomTemplateFiles,
];
}

/** @returns Filtered array based on the user selected generator option (component, module service or both component+module) */
Expand Down
12 changes: 7 additions & 5 deletions src/generator/settings.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
// Settings
// From package.json/contributes/configuration/properties
import * as vscode from 'vscode';

export const getSetting_customTemplateFolder = () =>
getExtensionSetting<string | null | undefined>('customTemplateFolder');

export const getSetting_defaultSpecsUseTestBed = () =>
getExtensionSetting<boolean | undefined>('defaultSpecsUseTestBed');

export const getSetting_generateSpec = () =>
getExtensionSetting<boolean | undefined>('generateSpec');

export const getSetting_generateStories = () =>
getExtensionSetting<boolean | undefined>('generateStories');

function getExtensionSettings(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration('angular-files-generator');
}

function getExtensionSetting<T>(settingKey: string): T | undefined {
return getExtensionSettings().get(settingKey);
}

function getExtensionSettings(): vscode.WorkspaceConfiguration {
return vscode.workspace.getConfiguration('angular-files-generator');
}
25 changes: 25 additions & 0 deletions src/templates-alt/__name__.component.spec.ts.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { {{upperCamelCaseName}}Component } from './{{dashCaseName}}.component';
import { {{upperCamelCaseName}}Module } from './{{dashCaseName}}.module';

describe('{{upperCamelCaseName}}Component', () => {
let component: {{upperCamelCaseName}}Component;
let fixture: ComponentFixture<{{upperCamelCaseName}}Component>;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [{{upperCamelCaseName}}Module],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent({{upperCamelCaseName}}Component);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
21 changes: 21 additions & 0 deletions src/templates-alt/__name__.directive.spec.ts.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import { {{upperCamelCaseName}}Directive } from './{{dashCaseName}}.directive';

describe('{{upperCamelCaseName}}Directive', () => {
let directive: {{upperCamelCaseName}}Directive;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
providers: [{{upperCamelCaseName}}Directive],
}).compileComponents();
}));

beforeEach(() => {
directive = TestBed.inject({{upperCamelCaseName}}Directive);
});

it('should create', () => {
expect(directive).toBeTruthy();
});
});
16 changes: 16 additions & 0 deletions src/templates-alt/__name__.module.spec.ts.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { {{upperCamelCaseName}}Module } from './{{dashCaseName}}.module';

describe('{{upperCamelCaseName}}Module', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [{{upperCamelCaseName}}Module],
});
});

it('should create', () => {
const module: {{upperCamelCaseName}}Module = TestBed.inject({{upperCamelCaseName}}Module);
expect(module).toBeTruthy();
});
});
16 changes: 16 additions & 0 deletions src/templates-alt/__name__.service.spec.ts.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { {{upperCamelCaseName}}Service } from './{{dashCaseName}}.service';

describe('{{upperCamelCaseName}}Service', () => {
let service: {{upperCamelCaseName}}Service;

beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject({{upperCamelCaseName}}Service);
});

it('should create', () => {
expect(service).toBeTruthy();
});
});
Loading

0 comments on commit 0c895e9

Please sign in to comment.