Skip to content

Latest commit

 

History

History
460 lines (351 loc) · 9.71 KB

README.md

File metadata and controls

460 lines (351 loc) · 9.71 KB

https://docs.cypress.io/guides/component-testing/angular/examples

1. ng-jest-cypress-template

Top 10 Angular Architecture Mistakes

https://angularexperts.io/blog/top-10-angular-architecture-mistakes

Not lazy loading ALL the features

Even a one-pager (single feature) application without navigation, this first page / feature should be implemented as the first lazy loaded feature!

I would personally recommend to always define lazy route with the routes based feature with loadChildren which is the most modern and flexible way of doing things. Then, in case our lazy feature contains sub navigation, we can lazy load additional components with loadComponent.

ng generate component --name features/home --inline-style --inline-template
// app.routes.ts
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: '',
    pathMatch: 'full',
    redirectTo: 'home',
  },
  // application with a single feature
  // implemented as a first lazy loaded feature
  {
    path: 'home',
    loadChildren: () =>
      import('./features/home/home.routes').then((m) => m.routes),
  },
];
// home.routes.ts
import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: '',
    loadComponent: () =>
      import('./home.component').then((m) => m.HomeComponent),
  },

  // which is easy to extend in the future, eg
  {
    path: 'editor',
    loadComponent: () =>
      import('./home-editor.component').then((m) => m.HomeEditorComponent),
  },

  // or a larger sub-feature
  {
    path: 'forecast',
    loadChildren: () =>
      import('./forecast/forecast.routes').then((m) => m.routes),
  },
];

Analyzing architecture manually instead of with the help of tooling

Madge

https://github.com/pahen/madge

npx madge src/main.ts --ts-config tsconfig.json --image ./deps.webp

Eslint plugin boundaries

https://github.com/javierbrea/eslint-plugin-boundaries

ESLINT_PLUGIN_BOUNDARIES_DEBUG=1 npm run lint

Firebase

Deploy Targets

firebase target:apply hosting main first-try-262cf
firebase target:apply hosting other my-site-e7a1
firebase deploy --only hosting:main
firebase hosting:channel:deploy preview --only main

1.1. Create project

This project was generated with Angular CLI version 12.2.8.

ng new ng-jest-cypress-template --style=scss --routing --strict

1.2. Add eslint

https://github.com/angular-eslint/angular-eslint

ng add @angular-eslint/schematics

1.3. Add prettier

1.3.1. Install

npm install --save-dev --save-exact prettier

1.3.2. Add .prettierignore

package.json
package-lock.json
dist
build

1.3.3. Add .prettierrc.json

{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "trailingComma": "es5",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "always",
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve",
  "endOfLine": "auto"
}

1.3.4. Install eslint-config-prettier:

npm install --save-dev --save-exact eslint-config-prettier

1.3.5. Update .eslintrc.json

{
  "extends": [
    "plugin:@angular-eslint/recommended",
    "plugin:@angular-eslint/template/process-inline-templates",
    "prettier"
  ]
}

1.3.6. Edit package.json

{
  "scripts": {
    "prettier:check": "prettier --check .",
    "prettier:write": "prettier --write ."
  }
}

1.4. Add jest

https://github.com/thymikee/jest-preset-angular

1.4.1. Remove karma & jasmine

npm remove karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter @types/jasmine jasmine-core
rm ./karma.conf.js ./src/test.ts

1.4.2. Install

npm install --save-dev --save-exact jest jest-preset-angular @types/jest

1.4.3. Create setup-jest.ts

In project root:

import 'jest-preset-angular/setup-jest';

1.4.4. Create jest.config.js

In project root:

require('jest-preset-angular/ngcc-jest-processor');

module.exports = {
  preset: 'jest-preset-angular',
  setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
  testPathIgnorePatterns: ['<rootDir>/cypress/'],
};

1.4.5. Edit tsconfig.json

See https://github.com/cypress-io/cypress-and-jest-typescript-example

{
  // Required for jest to work with cypress
  "include": ["src/*.ts"],
  "exclude": ["src/*.spec.ts"]
  //
}

1.4.6. Edit tsconfig.spec.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "esModuleInterop": true,
    "outDir": "./out-tsc/spec",
    "types": ["jest"]
  },
  "files": ["src/polyfills.ts"],
  "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}

1.4.7. Edit package.json

{
  "scripts": {
    // ...
    "test": "jest"
    // ...
  }
}

1.5. Add cypress

1.5.1. Websites

1.5.2. Install Cypress

npm install --save-dev --save-exact cypress
npx cypress open

1.5.3. Update cypress.json

{
  "baseUrl": "http://localhost:4200",
  "defaultCommandTimeout": 10000
}

1.5.4. Update package.json

{
  "scripts": {
    "cypress:open": "cypress open",
    "cypress:run": "cypress run"
  }
}

1.5.5. Add tsconfig.json

In cypress folder

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "sourceMap": false,
    "strict": true,
    "types": ["cypress"]
  },
  "include": ["**/*.ts"]
}

1.5.6. Add typescipt.spec.ts

In cypress/integration folder.

it('works', () => {
  cy.wrap('foo').should('equal', 'foo');
});

1.5.7. Add Angular test files

1.5.7.1. Add po.ts

In cypress\support folder.

// we could place this url into cypress.json as "baseUrl"
const url = 'http://localhost:4200';

export const navigateTo = () => cy.visit(url);

export const getGreeting = () => cy.get('.toolbar > span');

1.5.7.2. Add angular.spec.ts

In cypress\integrations\

import { navigateTo, getGreeting } from '../support/po';

describe('Hello Angular', () => {
  beforeEach(navigateTo);

  it('should display welcome message', () => {
    getGreeting().contains('Welcome');
  });
});

Extras

Jest paths mapping

Typescript config

{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@app/*": ["src/app/*"]
    }
  }
}

Jest config

module.exports = {
  /*
    https://kulshekhar.github.io/ts-jest/docs/getting-started/paths-mapping/

    tsconfig.json
    "paths": {
      "@app/*": ["src/app/*"]
    }
  */
  moduleNameMapper: {
    '^@app/(.*)$': '<rootDir>/src/app/$1',
  },
};

App Actions

eslint plugins

Jest

https://docs.cypress.io/guides/component-testing/component-test-troubleshooting