- 1. ng-jest-cypress-template
- Extras
- App Actions
https://docs.cypress.io/guides/component-testing/angular/examples
https://angularexperts.io/blog/top-10-angular-architecture-mistakes
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),
},
];https://github.com/pahen/madge
npx madge src/main.ts --ts-config tsconfig.json --image ./deps.webphttps://github.com/javierbrea/eslint-plugin-boundaries
ESLINT_PLUGIN_BOUNDARIES_DEBUG=1 npm run lintfirebase target:apply hosting main first-try-262cffirebase target:apply hosting other my-site-e7a1firebase deploy --only hosting:mainfirebase hosting:channel:deploy preview --only mainThis project was generated with Angular CLI version 12.2.8.
ng new ng-jest-cypress-template --style=scss --routing --stricthttps://github.com/angular-eslint/angular-eslint
ng add @angular-eslint/schematicsnpm install --save-dev --save-exact prettierpackage.json
package-lock.json
dist
build
{
"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"
}npm install --save-dev --save-exact eslint-config-prettier{
"extends": [
"plugin:@angular-eslint/recommended",
"plugin:@angular-eslint/template/process-inline-templates",
"prettier"
]
}{
"scripts": {
"prettier:check": "prettier --check .",
"prettier:write": "prettier --write ."
}
}https://github.com/thymikee/jest-preset-angular
npm remove karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter @types/jasmine jasmine-corerm ./karma.conf.js ./src/test.tsnpm install --save-dev --save-exact jest jest-preset-angular @types/jestIn project root:
import 'jest-preset-angular/setup-jest';In project root:
require('jest-preset-angular/ngcc-jest-processor');
module.exports = {
preset: 'jest-preset-angular',
setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
testPathIgnorePatterns: ['<rootDir>/cypress/'],
};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"]
//
}{
"extends": "./tsconfig.json",
"compilerOptions": {
"esModuleInterop": true,
"outDir": "./out-tsc/spec",
"types": ["jest"]
},
"files": ["src/polyfills.ts"],
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
}{
"scripts": {
// ...
"test": "jest"
// ...
}
}npm install --save-dev --save-exact cypressnpx cypress open{
"baseUrl": "http://localhost:4200",
"defaultCommandTimeout": 10000
}{
"scripts": {
"cypress:open": "cypress open",
"cypress:run": "cypress run"
}
}In cypress folder
{
"extends": "../tsconfig.json",
"compilerOptions": {
"sourceMap": false,
"strict": true,
"types": ["cypress"]
},
"include": ["**/*.ts"]
}In cypress/integration folder.
it('works', () => {
cy.wrap('foo').should('equal', 'foo');
});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');In cypress\integrations\
import { navigateTo, getGreeting } from '../support/po';
describe('Hello Angular', () => {
beforeEach(navigateTo);
it('should display welcome message', () => {
getGreeting().contains('Welcome');
});
});{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@app/*": ["src/app/*"]
}
}
}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',
},
};- https://glebbahmutov.com/blog/testing-angular-application-via-app-actions/
- https://www.cypress.io/blog/2019/01/03/stop-using-page-objects-and-start-using-app-actions/
- https://github.com/import-js/eslint-plugin-import
- https://github.com/jest-community/eslint-plugin-jest
- https://github.com/testing-library/eslint-plugin-jest-dom
- https://github.com/testing-library/eslint-plugin-testing-library
- https://github.com/testing-library/angular-testing-library/blob/main/apps/example-app/src/app/examples/02-input-output.spec.ts
- https://github.com/testing-library/jest-dom
- https://github.com/testing-library/user-event
https://docs.cypress.io/guides/component-testing/component-test-troubleshooting