Home

Awesome

angular-playground cypress version CircleCI

This repo is a copy of Angular's Karma examples, enhanced for innovation activities, best practices and information sharing.

Originally the repository was Siemens internal and used GitLab. It got migrated to Github and CircleCI, but the gitlab files have been left-in for a reference. Technically, this repo can be dropped in at gitlab.com and it would work, granted the runner tags are modified.

Improvements over the base application include:

Clone, cd in.

npm i       # installs
npm start   # serves

# on another tab

npm run test  # runs unit tests
npm run lint  # lints & fixes ts, css, html
npm run cypress:open       # starts cypress test runner against served app at localhost:4200
npm run cypress:run        # runs cypress tests headed against served app
npm run cypress:open-dev   # starts cypress test runner against deployed s3 static site at https://d1kaucldkbcik4.cloudfront.net

Links

CircleCI Pipelines

Cypress Dashboard

Combined coverage blog post

<br></br>

The original Karma example repo can be found here.

<details><summary>Migrating from Karma to Jest</summary>

Why use Jest?

You can do it manually, or automatically with Angular Jest Schematic from Briebug

To get started:

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

npm uninstall karma karma-chrome-launcher karma-coverage-istanbul-reporter karma-jasmine karma-jasmine-html-reporter @types/jasmine @types/jasminewd2 jasmine-core jasmine-spec-reporter

ng add @briebug/jest-schematic

The schematic will do these:

DELETE karma.conf.js
DELETE src/test.ts
CREATE jest.config.js (180 bytes)
CREATE setup-jest.ts (860 bytes)
CREATE test-config.helper.ts (611 bytes)
UPDATE package.json (1322 bytes)
UPDATE angular.json (3592 bytes)
UPDATE tsconfig.spec.json (330 bytes)

Instead of jest.config.js, move the settings to package.json. I like to add to package.json the settings in the manual instructions. Enhance this as you need it. Here is what I have in package.json:

  "jest": {
    "preset": "jest-preset-angular",
    "setupFilesAfterEnv": [
      "<rootDir>/setup-jest.ts"
    ],
    "testPathIgnorePatterns": [
      "<rootDir>/node_modules/",
      "<rootDir>/dist/"
    ],
    "globals": {
      "ts-jest": {
        "tsconfig": "<rootDir>/tsconfig.spec.json",
        "stringifyContentPathRegex": "\\.html$"
      }
    },
    "moduleNameMapper": {
      "@core/(.*)": "<rootDir>/src/app/core/$1"
    }
  }

I also like to replace default test script in package.json and add some new ones:

"scripts": {
  ...
  "test": "jest",
  "test:coverage": "jest --collectCoverage",
  "test:watch": "jest --watch",
}

In setup-jest.js, change the first line from import 'jest-preset-angular'; to import 'jest-preset-angular/setup-jest. This will get rid of the Jest warning when running tests. In a future version of briebug schematic, this may be taken care of.

Spying and mocking is different in Jest. You will have to change these manually.

If using Spectator, npm i -D @ngneat/spectator. In the spec files change import from '@ngneat/spectator' to import from '@ngneat/spectator/jest'.

</details>

<br></br>

<details><summary>PWA migration</summary>

PWA

A Service Worker is a script that runs in the web browser and manages caching for an application. Using a service worker to reduce dependency on the network can significantly improve the user experience.

<br> </br>

Add the service worker to the project

ng add @angular/pwa --project angular-unit-testing

<br> </br>

Verify the changes

<br>

Test that it works

Build in prod mode and locally test utilizing http-server package.

Service workers are only available in Prod mode.

Arrange:

ng build --prod

npm i -g http-server

http-server -p 8080 -c-1 dist/angular-unit-testing    ## -c-1 disables caching

Nav to http://127.0.0.1:8080 , use incognito.

Act:

Using Devtools > Network tab, turn the network off and refresh the app.

Assert:

The app should work as normal and the browser should not show disconnected page There is no Internet connection.

Devtools > Network tab > Size column should show value (Service Worker) for the network resources.

Additional test Devtools > Application tab > and choose Service Workers on the left. You should see that the service worker is enabled.

</details>

<br></br>

<details><summary>Setup Cypress</summary>

Migrate from Protractor to Cypress

This will replace Protractor with Cypress and update your dependencies and project files.

npm install -g @briebug/cypress-schematic
ng add @briebug/cypress-schematic

You can optionally leave the changes it makes to angular.json, and package.json they do not do harm. Personally I do not utilize them. So I remove the "e2e", "cypress-run" and "cypress-open" properties from angular.json. I also remove the briebug/cypress-schematic package from package.json.

  "e2e": { ...
  },
  "cypress-run": { ...
  },
  "cypress-open": { ...
  }

Core recommended settings

Start Cypress

Serve your app with npm run start and on another tab start Cypress with npm run cypress:open.

To execute the tests in CI or without the test runner UI locally, use npm run cypress:run.

</details>

<br></br>

<details><summary>Setup CI</summary>

CI

</details>

<br></br>

<details><summary> Setup Combined Coverage</summary>

Follow the blog post for a detailed walk-through of combined code coverage setup.

</details>

<br></br>

<details><summary>Setup lint</summary>

Setup eslint

Tip: to create a new Angular project with eslint

ng new --collection=@angular-eslint/schematics

Setup prettier code formatter

npm i -D prettier eslint-config-prettier eslint-plugin-prettier

You can find recommended configurations for .prettierrc.js, prettierignore and .vscode/settings.json files in the final version of the repository.

Get the vs code extension.

Add prettier rule to .eslintrc.json.

"extends": [
  "plugin:prettier/recommended",
  "plugin:@angular-eslint/ng-cli-compat",
  "plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
  "plugin:@angular-eslint/template/process-inline-templates",
  "plugin:jest/recommended",
  "plugin:jest/style",
],

Now if we run ESLint with --fix flag, it will use Prettier to auto format code, solving both stylistic and semantic problems.

Setup js-beautify for css and or html

npm i -D js-beautify

Create a .jsbeautifyrc file. You can find recommended configurations for the file in the final version of the repository.

Get the vscode extension.

Enhance package.json "lint": "ng lint --fix && npx js-beautify src/**/*.css"

Setup stylelint for css (optional)

The findings were too many to fix in this project, best to start with stylelint and not do it later.

Helps you avoid errors and enforce conventions in your styles.

npm i -D stylelint stylelint-config-standard

Setup husky pre-commit hook

Can execute lint and unit test prior to git push.

To skip pre-commit hooks, use -n / --no-verify commit message modifier.

npm i -D husky

Add to package.json the pre-commit hook

"husky": {
  "hooks": {
    "pre-commit": "npm run lint && npm run test"
  }
}

If husky is not working on commit:

rm -rf .git/hooks/
npm remove husky
npm i -D husky

If still does not work, use an older version of husky, like the one in this repo's package.json.

</details>

<br></br>

<details><summary>Deploy the Angular single page app to AWS S3 as a static website</summary>
Compiled angular -> | S3 | <-> | CloudFront |  <--> Internet
  (/dist folder)    +----+     +------------+

(source)

"You can use Amazon S3 to host a static website. On a static website, individual webpages include static content, in contrast to a dynamic website which relies on server-side processing."

  1. Locally, run ng build --prod to populate your app's dist folder; ex: dist/angular-unit-testing.

  2. Log in to your AWS account and nav to S3 console.

  3. Create a bucket. Enter a bucket name (ex: angular-cypress-jest-playground), and select an AWS Region (ex: us-east-1).

  4. Unblock all public access. The default is Block all public access. The other settings are optional, in this repo's workflow they have been skipped.

  5. At your bucket default view (Amazon S3 > angular-cypress-jest-playground > Objects) click upload, Add files, and select the files at your app's dist folder (i.e. dist/angular-unit-testing).

  6. Under Permissions, choose Grant public-read access. All the other settings are optional. Hit Upload and wait a few seconds. Then you can Close the view and get back to Amazon S3 > angular-cypress-jest-playground > Objects.

  7. Nav to Properties tab (Amazon S3 > angular-cypress-jest-playground > Properties). At the bottom, Edit Static website hosting and Enable it. For both Index document and Error document enter index.html.

You should be able to access your site at http://<bucket-name>.s3-website-<region>.amazonaws.com , or namely http://angular-cypress-jest-playground.s3-website-us-east-1.amazonaws.com

Important note about setting Error document to index.html

Choosing index.html for Error document is a hacky way of getting around errors that would happen when using Angular's routing mechanism. For example, do not set Error Document, go to the url, and then copy paste a route to the browser (ex: http://angular-cypress-jest-playground.s3-website-us-east-1.amazonaws.com/heroes/15). You will get a 403 forbidden error, which you would not see if you were locally serving your application.

Make it better by using CloudFront

CloudFront is a content delivery network. "When a user requests content that you're serving with CloudFront the request is routed to the edge location that provides the lowest latency (time delay), so that content is delivered with the best possible performance".

We can configure CloudFrount so that whenever S3 replies with 403 or 404, we return content from index.html and respond with status 200.

  1. Go to CloudFront Console > Create new Distribution > Get Started. You should be at Create Distribution form.

  2. Origin Domain name: select the s3 bucket we created angular-cypress-jest-playground.s3.amazonaws.com

  3. Default Cache Behavior Settings > Allowed HTTP Methods: select Redirect HTTP to HTTPS

  4. (optional) Distribution Settings > Alternate Domain Names : you can pick a name here for example just angular-cypress-jest-playground, but you would have to use AWS Route 53 to register that domain name for $12/year. (Did not do this for this example).

  5. Default Root Object: enter index.html.You can leave everything else default and save.

  6. You should be at CloudFront Distributions. Put a check mark on the distribution and go to Distribution Settings > Error Pages > Create Custom Error Response.

  7. You will create 2 custom error responses for 403 and 404. Each should have Response Page Path: /index.html and HTTP Response Code: 200: OK.

Our alternate url is https://d1kaucldkbcik4.cloudfront.net.

You can now make 3 changes to the test architecture, so that master pipeline runs against this new url.

  1. set cypress/config/dev.json file's baseUrl as https://d1kaucldkbcik4.cloudfront.net.
  2. add a script to package.json to run tests againt the dev deployment: "cypress:open-dev": "cypress open --config-file cypress/config/dev.json"
  3. create a master pipeline / dev deployment e2e test job. Refer to cypress/.gitla-ci-tests.yml .dev_template: &dev job for details.

Note: in the real world you would have infra as code, and the deployments would be targeting S3 automatically, without us having to manually deploy the app. This process is not a part of the repo here.

</details>