Coder Social home page Coder Social logo

gparlakov / scuri Goto Github PK

View Code? Open in Web Editor NEW
66.0 4.0 6.0 9.55 MB

Automate Angular unit test and boilerplate with this schematic.

License: MIT License

TypeScript 98.17% JavaScript 0.16% Shell 1.24% Dockerfile 0.26% PowerShell 0.16%
angular unittest unittests-generation typescript schematics spec-schematic boilerplate enterprise

scuri's Introduction

SCuri*

Build Status

All Contributors

Automates unit test boilerplate for Angular components/services/directives/etc. It will generate spec for you and help you update it when dependencies are added or removed!


Powered by Schematics and TypeScript compiler

Links

VS Code extension available!

๐Ÿฑโ€๐Ÿ‘คNeed a custom template?

๐Ÿค™Have some feedback or need a feature? SCuri discussion on github

๐ŸคตNeed commercial-quality coverage for SCuri?

๐Ÿ’ตSupport us

Why?

After a component has been created it is boring and tedious to do the tests - and we often don't. SCuri* tries to jump-start that by walking the component's constructor, parsing the dependencies and creating mocks for each of them, and then including them in the spec.

Features

Create a test case from scratch

missing create spec video

The video shows how to use schematics scuri:spec --name src\app\my-com\my-com.component.ts to create a spec from scratch (if already created see update or use --force to overwrite).

For Angular CLI >= 6 ng g scuri:spec --name src\app\my-com\my-com.component.ts could be used instead.

--name is now optional ng g scuri:spec my-com.component.ts or npx schematics scuri:spec my-com.component.ts

See details down here.

Update existing test

missing update spec video

Shows how we begin with an outdated test:

  • missing it test case for one of the public methods (getData)
  • missing dependency HttpClient to instantiate the component

And after schematics scuri:spec --name src\app\my-com\my-com.component.ts --update command we get the updated test - dependency and a scaffold test case added.

For Angular CLI >= 6 ng g scuri:spec --name src\app\my-com\my-com.component.ts --update could be used instead.

See details down here

AutoSpy

missing autospy video Generates an autoSpy function that takes a type and returns an object with the same type plus all its methods are mocked i.e. jasmine.spy() or jest.fn().

See details down here. Needs tsconfig path setup -> there.

Getting started / Setup

Using VS Code? Just install the SCuri VS Code extension

Command line setup

  1. Install deps

    npm install -D scuri
    ng g scuri:spec --name src/app/app.component.ts
  2. Generate autospy

    ng g scuri:autospy

    Details and older Angular versions

  3. Tell Typescript where to find autoSpy by adding autoSpy to paths:

    {
        ...
        "compilerOptions": {
            ...
            "baseUrl": ".",
            "paths": {
                "autoSpy": ["./src/auto-spy"]
            }
        }
    }

    Details here

  4. Start using scuri:

    ng g scuri:spec --name src/app/app.component.ts

If you get Error: Invalid rule result: Function(). see the troubleshooting section below.

Details

Create spec from scratch

ng g scuri:spec --name src/app/app.component.ts

or

npx schematics scuri:spec --name src/app/app.component.ts

Requires --name - an existing .ts file with one class (Component/Service/Directive/etc.) and NONE existing .spec.ts file.

Overwrite existing spec

ng g scuri:spec --name src/app/app.component.ts --force

or

npx schematics scuri:spec --name src/app/app.component.ts --force

Requires --name - an existing .ts file with one class (Component/Service/Directive/etc.). Will overwrite any existing .spec.ts file.

This might be useful in certain more complex cases. Using a diff tool one could easily combine the preexisting and newly created (overwritten) content - just like a merge conflict is resolved.

Update existing spec

ng g scuri:spec --name src/app/app.component.ts --update

or

npx schematics scuri:spec --name src/app/app.component.ts --update

Requires --name - an existing .ts file with one class (Component/Service/Directive/etc.) and one existing .spec.ts file where the update will happen.

AutoSpy

To generate an auto-spy.ts file with the type and function which can be used for automating mock creation, use:

ng g scuri:autospy

See the Autospy wiki page.

Using older versions of Angular?

  • Angular v5, v4, v2: bash npm i -g @angular-devkit/schematics-cli npm i -D scuri schematics scuri:autospy --legacy Notice the --legacy flag. It's required due to typescript being less than 2.8. See flags below

Using Jest

ng g scuri:autospy --for jest

Or

schematics scuri:autospy --for jest

Versions and flags

angular jest / jasmine command
2,4,5 jasmine schematics scuri:autospy --legacy
jest schematics scuri:autospy --for jest --legacy
6, 7, 8 and up jasmine ng g scuri:autospy
jest ng g scuri:autospy --for jest

All Angular versions after and including 6 can use the Angular CLI - ng generate scuri:autospy.

Flags:

  • --for with accepted values jest and jasmine (default is jasmine)
  • --legacy for generating a type compatible with typescript < 2.8 (namely the conditional types feature)

Examples: ng g scuri:autospy --for jest --legacy would generate a ts<2.8, jest-compatible autoSpy type and function ng g scuri:autospy would generate a ts>2.8, jasmine-compatible autoSpy type and function

Autospy and Typescript

After creating the auto-spy.ts file as a result of the scuri:autospy schematic invocation we need to make sure its properly imported in our tests. To that end and keeping in mind that autoSpy is being imported in the created tests as import { autoSpy } from 'autoSpy';. To make that an actual import one could add this line to tsconfig.json:

{
    "compilerOptions": {
        "baseUrl": ".", // This must be specified if "paths" is.
        "paths": {
            "autospy": ["./src/auto-spy"] // This mapping is relative to "baseUrl"
        }
    }
}

This is assuming auto-spy.ts was created inside ./src folder. Edit as appropriate for your specific case.

See here for path details

๐Ÿ›ฃ Road map ~

  • Create spec from scratch (or overwrite existing with --force)
  • Update existing spec - add/remove dependencies
  • Create one scaffold it test case for each public method
  • On Update add it-s for newly added public methods
  • Generate autoSpy by scuri:autospy (support jest, jasmine and ts with and w/o conditional types)
  • Support traditional Angular cli generated tests (with --update)
    • Add setup function when missing
    • Update dependencies
  • Allow configuration via file (.scuri.json)
  • (workaround) Import autoSpy function automatically - now imported as import { autoSpy } from 'autoSpy';

S.C.u.r.i. *

What's with the name?

A spec generator schematic - Spec Create Update Read (class - component, service, directive and dependencies) Incorporate (them in the spec generated/updated)

Configuring

Scuri can use configuration from the following list by default (package.json .scurirc .scurirc.json .scurirc.yml .scurirc.yaml scurirc.js scurirc.config.js).

Example package.json

{
  "name": "my-app",
  ...
  "scuri": {
      "classTemplate": "src/templates/__specFileName__.template",
      "functionTemplate": "src/templates/__specFileName__.template"
  }
}

Example .scurirc

{
    "classTemplate": "src/templates/__specFileName__.template",
    "functionTemplate": "src/templates/__specFileName__.template"
}

Custom templates

Head over to the custom template guide or see the short explanation below:

  • classTemplate - a location of a custom class template to be used. Here's a gist of starter template that explains what properties are available to the class template
  • functionTemplate - a location of a custom function template to be used. Here's a gist of a starter template that shows what properties are available to the function template

Troubleshooting

Migrating from 1.1 to 1.2 broke the custom template!

Try using __specFileName__.template for your template name. The __specFileName__ gets interpreted while creating the spec. There are other variables available too - see the custom template guide

Rule result Function

To workaround the Error: Invalid rule result: Function(). install schematics separately and call scuri with that.

npm install -D scuri
npm i -g @angular-devkit/schematics-cli
schematics scuri:spec --name src/app/app.component.ts

or if you don't want to install the schematics cli globally and have npm version 6 and above you can

npm install -D scuri @angular-devkit/schematics-cli
npx schematics scuri:spec --name src/app/app.component.ts

Contributing

Link

SCuri for enterprise

Available as part of the Tidelift Subscription

The maintainers of SCuri and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open-source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.

Contributors โœจ

Thanks goes to these wonderful people (emoji key):


Georgi Parlakov

๐Ÿ’ป ๐Ÿค” ๐Ÿ“– โš ๏ธ

Tzi Yang

๐Ÿ›

fgisslen

๐Ÿ›

danjor

๐Ÿ›

Dependabot

๐Ÿšง

OSHistory

๐Ÿ› ๐Ÿ’ป

This project follows the all-contributors specification. Contributions of any kind welcome!

Like it?

You like the project and it gives you value? You are considering supporting it? That would be really appreciated!

โ˜•Buy us a coffee

scuri's People

Contributors

allcontributors[bot] avatar dependabot[bot] avatar gparlakov avatar oshistory avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

scuri's Issues

Import dependencies

We can take the dependencies imports from the file under test and import them in the spec.

  • Simple case - all dependencies (except for simple types) are imported - find the import statements from the example.component.ts and copy paste them in the example.component.spec.ts

Future:

  • More complex - some deps are local to the file - find them
  • If we support output path not next to the file-under-test we'll need to calculate imports in the generated file

Methods with parameters have no parameters on test

Some methods have parameters but on spec created by SCuri no parameters is passed. Here is the original TS:

import { Component, OnInit, ViewEncapsulation, AfterViewInit, ViewChild, DoCheck, HostListener } from '@angular/core';
import { DocumentoTypes } from '../shared/model/documento.types';
import { LoginPainelConnectClient } from '../shared/model/login-painel-connect-client.model';
import { FormSimples } from '../../components/arquitetura/arquitetura-form/arquitetura-form.model';
import { AlertService } from '../../components/alert/_services';
import { Router, ActivatedRoute } from '@angular/router';
import { LoginPainelConnectClientService } from '../shared/services/login-painel-connect-client.service';
import { StringUtils } from '../../components/util/date/string-utils';
import { Cookie } from 'ng2-cookies';
import { EmpresasApiService } from '../../components/api-empresas/_service/api-empresas.service';
import { HttpParams } from '@angular/common/http';
import { BsModalService } from 'ngx-bootstrap';
import { ModalLoginEmpresaComponent } from './modal/modal-login-empresa/modal-login-empresa.component';
import { environment } from '../../../environments/environment';
import { AlertComponent } from '../../components/alert/_directives';

@Component({
  selector: 'app-login-painel-connect-client',
  templateUrl: './login-painel-connect-client.component.html',
  encapsulation: ViewEncapsulation.None,
  styleUrls: ['./login-painel-connect-client.component.scss', '../endless.css', '../endless-skin.css']
})
export class LoginPainelConnectClientComponent implements OnInit, AfterViewInit, FormSimples {

  login: LoginPainelConnectClient = new LoginPainelConnectClient();
  alertConfigs = this.alertService.configListStyle();
  documentoLogin = '';
  maxlength = 18;
  documentoDefault: DocumentoTypes = DocumentoTypes.CNPJ;
  documentos: Array<DocumentoTypes> = [this.documentoDefault, DocumentoTypes.CPF, DocumentoTypes.CAEPF, DocumentoTypes.CEI];
  documentoSelecionado = this.documentoDefault;
  placeHolderDocumento = 'CNPJ da sua empresa';

  isNotValidApelido = false;
  isNotValidDocumento = false;
  isNotValidLogin = false;
  isNotValidSenha = false;

  returnUrl: string;

  @ViewChild('alertaComponent')
  alertaComponent: AlertComponent;

  constructor(
    private readonly loginService: LoginPainelConnectClientService,
    private readonly alertService: AlertService,
    private readonly empresaService: EmpresasApiService,
    private readonly modalService: BsModalService,
    private readonly route: ActivatedRoute) { }

  ngOnInit() {
  }

  ngAfterViewInit(): void {
    this.alertaComponent.isPainelConnectClient = true;
    this.returnUrl = this.route.snapshot.queryParamMap.get('redirect');
  }

  @HostListener('window:keyup', ['$event'])
  keyEvent(event: KeyboardEvent) {
    if (event.keyCode === 13) {
      this.btnConfirmar();
    }
  }


  changeDocumentoSelecionado(documento: DocumentoTypes) {
    this.documentoSelecionado = documento;
    this.documentoLogin = '';
    this.getDocumentoPlaceHolder(this.documentoSelecionado)
  }

  transform() {
    let documento = this.documentoLogin;
    switch (this.documentoSelecionado) {
      case DocumentoTypes.CNPJ:
        documento = documento.replace(/^(\d{2})(\d)/, '$1.$2');
        documento = documento.replace(/^(\d{2})\.(\d{3})(\d)/, '$1.$2.$3');
        documento = documento.replace(/\.(\d{3})(\d)/, '.$1/$2');
        documento = documento.replace(/(\d{4})(\d)/, '$1-$2');
        break;
      case DocumentoTypes.CPF:
        documento = documento.replace(/(\d{3})(\d)/, '$1.$2');
        documento = documento.replace(/(\d{3})(\d)/, '$1.$2');
        documento = documento.replace(/(\d{3})(\d{1,2})$/, '$1-$2');
        break;
      case DocumentoTypes.CEI:
        documento = documento.replace(/(\d{2})(\d{3})(\d{5})(\d{2})/, '$1.$2.$3/$4'); // Mascara CEI (99.999.99999/99)
        break;
      case DocumentoTypes.CAEPF:
        documento = documento.replace(/(\d{3})(\d{3})(\d{3})(\d{3})(\d{1})/, '$1.$2.$3/$4-$5'); // 13 caracteres
        documento = documento.replace(/(\d{3})(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3/$4-$5'); // 14 caracteres - Mascara CAEPF (999.999.999/999-99)
        break;
    }
    this.documentoLogin = documento;
  }

  isValidForm(): boolean {
    let isValid = true;
    if (!this.login.apelido) {
      isValid = false;
      this.validarApelido();
    }
    if (!this.documentoLogin) {
      isValid = false;
      this.validarDocumento();
    }
    if (!this.login.login) {
      isValid = false;
      this.validarLogin();
    }
    if (!this.login.senha) {
      isValid = false;
      this.validarSenha();
    }
    return isValid;
  }

  btnCancelar(): void {
    throw new Error("Method not implemented.");
  }

  btnConfirmar(): void {
    if (this.isValidForm()) {
      this.alertService.clear();
      this.login.documento = StringUtils.replaceAll(this.documentoLogin, '', '[\/\\.-]');
      this.empresaService.getEmpresasByApelidoClienteAndDocumento(this.login.apelido, this.login.documento, null).subscribe(resourceEmpresas => {
        if (resourceEmpresas.content && resourceEmpresas.content.length > 1) {
          const initialState = {
            empresas: resourceEmpresas.content,
            login: this.login,
            alertConfigs: this.alertConfigs,
            returnUrl: this.returnUrl
          }
          this.modalService.show(ModalLoginEmpresaComponent, { initialState, ignoreBackdropClick: true, class: "modal-sm" })
        } else {
          this.loginService.obterToken(this.login, this.alertConfigs, this.returnUrl);
        }
      });
    }
  }

  validarApelido() {
    setTimeout(() => {
      if (!this.login.apelido) {
        this.isNotValidApelido = true;
      } else {
        this.isNotValidApelido = false;
      }

    }, 1);
  }

  validarDocumento() {
    this.transform();
    if (!this.documentoLogin) {
      this.isNotValidDocumento = true;
    } else {
      this.isNotValidDocumento = false;
    }
  }

  validarLogin() {
    setTimeout(() => {
      if (!this.login.login) {
        this.isNotValidLogin = true;
      } else {
        this.isNotValidLogin = false;
      }
    }, 1);
  }

  validarSenha() {
    setTimeout(() => {
      if (!this.login.senha) {
        this.isNotValidSenha = true;
      } else {
        this.isNotValidSenha = false;
      }
    }, 1);
  }

  public getDocumentoPlaceHolder(documento: DocumentoTypes) {

    if (documento === DocumentoTypes.CNPJ) {
      this.placeHolderDocumento = 'CNPJ da sua empresa';
      this.maxlength = 18;
    }

    if (documento === DocumentoTypes.CPF) {
      this.placeHolderDocumento = 'CPF da sua empresa';
      this.maxlength = 14;
    }

    if (documento === DocumentoTypes.CAEPF) {
      this.placeHolderDocumento = 'CAEPF da sua empresa';
      this.maxlength = 18;
    }

    if (documento === DocumentoTypes.CEI) {
      this.placeHolderDocumento = 'CEI da sua empresa';
      this.maxlength = 15;
    }

  }

}

and here is the SPEC, with errors on getDocumentoPlaceHolder, changeDocumentoSelecionado and keyEvent methods.

import { LoginPainelConnectClientService } from '../shared/services/login-painel-connect-client.service';
import { AlertService } from '../../components/alert/_services';
import { EmpresasApiService } from '../../components/api-empresas/_service/api-empresas.service';
import { BsModalService } from 'ngx-bootstrap';
import { ActivatedRoute } from '@angular/router';
import { LoginPainelConnectClientComponent } from './login-painel-connect-client.component';
import { autoSpy } from 'src/auto-spy';

describe('LoginPainelConnectClientComponent', () => {
  it('when ngOnInit is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.ngOnInit();
    // assert
    // expect(c).toEqual
  });

  it('when ngAfterViewInit is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.ngAfterViewInit();
    // assert
    // expect(c).toEqual
  });

  it('when keyEvent is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.keyEvent();
    // assert
    // expect(c).toEqual
  });

  it('when changeDocumentoSelecionado is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.changeDocumentoSelecionado();
    // assert
    // expect(c).toEqual
  });

  it('when transform is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.transform();
    // assert
    // expect(c).toEqual
  });

  it('when isValidForm is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.isValidForm();
    // assert
    // expect(c).toEqual
  });

  it('when btnCancelar is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.btnCancelar();
    // assert
    // expect(c).toEqual
  });

  it('when btnConfirmar is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.btnConfirmar();
    // assert
    // expect(c).toEqual
  });

  it('when validarApelido is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.validarApelido();
    // assert
    // expect(c).toEqual
  });

  it('when validarDocumento is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.validarDocumento();
    // assert
    // expect(c).toEqual
  });

  it('when validarLogin is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.validarLogin();
    // assert
    // expect(c).toEqual
  });

  it('when validarSenha is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.validarSenha();
    // assert
    // expect(c).toEqual
  });

  it('when getDocumentoPlaceHolder is called it should', () => {
    // arrange
    const { build } = setup().default();
    const c = build();
    // act
    c.getDocumentoPlaceHolder();
    // assert
    // expect(c).toEqual
  });

  
});

function setup() {
  const loginService = autoSpy(LoginPainelConnectClientService);
const alertService = autoSpy(AlertService);
const empresaService = autoSpy(EmpresasApiService);
const modalService = autoSpy(BsModalService);
const route = autoSpy(ActivatedRoute);
  const builder = {
    loginService,
alertService,
empresaService,
modalService,
route,
    default() {
      return builder;
    },
    build() {
      return new LoginPainelConnectClientComponent(loginService,alertService,empresaService,modalService,route);
    }
  };

  return builder;
}

Check for the "Nothing to update" case

If there is nothing to update do nothing(and tell the user).

Perhaps in the case of generate we can do that too... (or maybe it will be too complicated what with the --force flag being a possibility)

file missing or empty

in vs code i open terminal in directory of ts file I want to build spec for.
doing bash 'ls' shows the x.ts file i want to test
$ ng g scuri:spec --name x.ts (in same directory of x.ts)

error message: Params: name: x.ts update: false
The file x.ts is missing or empty.
Nothing to be done.

The file is there, what can I do?

First letter Shorthand error

I have minor issue related to shorthand by class first letter, when update (fine on create) specs files.
It works unequal on declare build class and use declaration.

For exemple on my ProductDetailsComponent it generates this code:
it('when ngOnInit is called it should', () => { // arrange const { build } = setup().default(); const p = build(); // act c.ngOnInit(); // assert // expect(c).toEqual });

On declare build results it works properly but not on calls methods and do "expect" that use old shorthand based on file type.

Thanks

Format the output

At present we do not try to format the generated output.
There is a TslintFixTask (see src and tests). Maybe we can leverage that.

Thin out deps

See if we can get rid of some dependencies like jsonc-parse (added with the big update) and remove the dependencies from unused utilities...

When spec not existing the error is misleading

...Can not update null since it does not exist...

ERROR:             Can not update null since it does not exist. Try running without the --update flag.

CONSOLE:             Params: name: src/polyfills.ts update: true
Nothing to be done.

Support traditional tests

  • allow update to work on files without setup function (and actually create it)
  • use the setup function in the beforeEach where the TestBed is configured and provide all required dependencies

Detect autoSpy when importing

When creating/updating a spec detect autoSpy (by going up folders until .angular-cli.json or angular.json) and import that in the specs.

Update existing spec files

At present we only create or overwrite (when --force flag passed) the spec file.
We need to keep the contents of the already created spec file - it tests, setup boilerplate, etc. and only update them

  • Recognize there is already a file with that name and kick into update mode
  • Find the delta dependencies - removed and update the setup boilerplate removes
  • Find the delta dependencies - added and update the setup boilerplate removes
  • Read the spec file tests (it calls) and only add new ones for new public methods

Important:
This work is only for scuri generated spec files or spec files that follow the setup() function with a builder object getting returned from it.

Guess (or null) method call arguments

When in a test we call a method - try and get it's call arguments or pass null

class UnderTest {
  method(p: number, o: Service) {
  /// implementation
  }
}
//// test
const o = autoSpy(Service);
c.method(0, o)

Add a comma in the beginning of the deps list

If there are any existing dependencies - add a prefix-comma in the instantiation class-under-test dependencies list.

Or Just redo the whole list as its order matters - the order of deps matters for the constructor.

Spec on autoSpy.ts

Is there a spec file to test the autoSpy.ts file ?
export function autoSpy

Or can you tell me how to test it ?

Because Sonar is not happy with the fact that it's not tested :(
image

Thank you !

export SpyOf

It is declared but not exported (jasmine for sure, maybe all?)

Make tests for any public method

At present the logic omits the async methods. Perhaps others
It would be nice to do a test for any non-private method i.e. if the flags do not include private (from enum)

Adhere to --force

Now we throw if the file exists and do not check if user passed in the --force flag.
We need to check for it (--force) and allow user to overwrite

Accept existing tests for describe and name of method

Logic of creating new test cases relies on the when methodName but people can actually not call the test with the method name so we should check for existence of the methodName only anywhere in the spec test, including describe and spec body

React Support

Hi! @gparlakov I want to use Scuri to automate test case generation for react web apps in my organization. Can Scuri be used with react apps? If no, is there any other tool that you would recommend? In case the answer to both of the questions is no, where can i get a code tour of scuri so that i can understand it and can modify or write something of my own that would work with react!
Thanks

Correct imports

  • only import missing modules
  • do not duplicate imported modules

Allow configuration from package.json or .scuri.json

We'd like to be able to configure things like:

  • it name - i.e. now hard-coded default when <method> is called it should ...
  • jest/jasmine
  • ts version - with or without conditional types
  • default or Angular version tests - i.e. to call setup() in every test case or rely on TestBed plus inject and test-global value
  • autospy location
    etc.
    • allow config file (.scurirc, package.json, ..., --config cli arg for custom file)
    • config custom class template
    • config custom function template
    • respect config in test names
    • configure location of autospy
    • configure setup function name use custom templates for that
    • configure whether to add tests for new methods (per test file, per execution of scuri:spec) use custom templates for that
    • configure if try to add support for Angular Standard method (per test file, per execution of scuri:spec) use custom templates for that

Create a spec file when there is at least one function in file

example

export function stringIsEmpty(obj: string): boolean {
    return obj == null || obj === '' || obj.trim() === '';
}

scuri says :

...scuri/src/collection.json:spec --name "src/app/core/string-is-empty.ts"  --debug false
            No classes found to be spec-ed!
 (ERROR LINE)
            Params: name: src/app/core/string-is-empty.ts update: false
Nothing to be done.

Abstract classes

First of all, thanks for the great tool, much appreciate it. I do got some issue though. I have few abstract components that I also want to test, but when I run ng test it gives an error at the build function: Cannot create an instance of an abstract class.ts(2511). I could make a new class and extend it with this component. This will solve the issue, but maybe there is an other way?

Secondly, is it possibly to generate the spec files through scanning a directory? Just like the angular-spec-generator package.

Use `branchMerge` to create auto-spy.ts where user is

At present the auto-spy.ts file is generated at the base of the tree and needs to be moveed to where it's supposed to be. Need to use the appropriate function to create it on the spot required in the first place

Mitigate Security warnings for the example projects

We now get a lot of security warnings caused by the example projects' package.json referencing old and vulnerable packages. These really do not put the end user at risk.

Examples are useful while developing and testing the features so it we could:

  • move the examples in a separate repo - simple but adds a level of indirection for contributors...
  • have a setup script to set dev environment up and generate the examples on the fly - complex, but simple for contributors ...

auto-spy jest code issue - cannot find name jest

Following the steps you provide, when generating the auto-spy file

autoSpy Function:
` // turns out that in target:es2015 the methods attached to

the prototype are not enumerable so Object.keys returns []. So to workaround that and keep some backwards compatibility - merge with ownPropertyNames - that disregards the enumerable property.

const keys = [...Object.keys(obj.prototype), ...Object.getOwnPropertyNames(obj.prototype)];
keys.forEach(key => {
res[key] = jest.fn();
});`

VS code thowr an error saying: Cannot find name 'jest'
res[key] = jest.fn();

same it export type SpyOf<T> = T & { [k in keyof T]: T[k] extends (...args: any[]) => infer R ? T[k] & jest.Mock<R> : T[k]; };

Is there any fix, is something change?

Screen Shot 2020-12-08 at 15 13 16

Calls method of service in component doesn't work

Hi,
I created a test of a component with scuri.
The component calls a service function in the constructor.

When the test tries to build it get's the error: TypeError: this.authService.loggedIn is not a function.

Does anyone have a clue on why this is happening?

Handle public static methods

Now SCuri creates a test method and an instance for static methods.

class Static {
  static method() {}
}

// test
it('when method is called', () => {
   const s = setup().build();
   s.method(); 
   // ^^ this is error since the method is static and can not be invoked on the instance
})

When Update - add missing `it` tests

When we are updating we want to also add the missing it tests. That is - for every public method we want to have at least one it test so if any methods are missing an it test - go ahead and add one

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.