├── .gitignore ├── README.md ├── temperature-basic ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── bin │ └── env_setup ├── exam.txt ├── karma.conf.js ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ └── temperatureConverter │ │ │ ├── temperatureConverter.component.html │ │ │ ├── temperatureConverter.component.scss │ │ │ ├── temperatureConverter.component.spec.ts │ │ │ └── temperatureConverter.component.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ └── text.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json └── weather-details ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── bin └── env_setup ├── exam.txt ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── app │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ └── weatherDetails │ │ ├── weatherDetails.component.html │ │ ├── weatherDetails.component.scss │ │ ├── weatherDetails.component.spec.ts │ │ └── weatherDetails.component.ts ├── assets │ └── .gitkeep ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss └── test.ts ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | **/unit.xml 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular 2 | 3 | 4 | ### Temperature-Converter 5 | 6 | ### Weather-Details 7 | -------------------------------------------------------------------------------- /temperature-basic/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /temperature-basic/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /temperature-basic/README.md: -------------------------------------------------------------------------------- 1 | # Temperature Converter 2 | 3 | ## Environment 4 | 5 | - Angular CLI Version: 10.0.4 6 | - Angular Core Version: 10.0.4 7 | - Node Version: 12.18.3 8 | - Default Port: 8000 9 | 10 | ## Application Demo: 11 | 12 | ![](https://hrcdn.net/s3_pub/istreet-assets/-Y4byw48oCxRPaW0kiNlyA/temperature-converter.gif) 13 | 14 | ## Functionality Requirements 15 | 16 | - It has 2 input number fields. The first is for a Celsius value, and the second is for a Fahrenheit value. 17 | 18 | - Initially, both fields are empty. 19 | 20 | - As a value is typed into the Celsius field, convert it to Fahrenheit and show it in the Fahrenheit field. Use the formula `F = C*9/5 + 32` for conversion. In case of decimals, show up to 1 decimal value. 21 | 22 | - As a value is typed into the Fahrenheit field, convert it to Celsius and show it in the Celsius field. Use the formula `C = (F − 32) × 5/9` for conversion. In case of decimals, show up to 1 decimal value. 23 | 24 | ## Testing Requirements 25 | 26 | - The Celsius input should have the data-test-id attribute 'celsius-input'. 27 | - The Fahrenheit input should have the data-test-id attribute 'fahrenheit-input'. 28 | 29 | ## Project Specifications 30 | 31 | **Read-only Files** 32 | - src/app/temperatureConverter/temperatureConverter.component.spec.ts 33 | - src/app/app.component.spec.ts 34 | - src/app/app.component.ts 35 | - src/app/app.module.ts 36 | 37 | **Commands** 38 | - run: 39 | ```bash 40 | bash bin/env_setup && . $HOME/.nvm/nvm.sh && npm start 41 | ``` 42 | - install: 43 | ```bash 44 | bash bin/env_setup && . $HOME/.nvm/nvm.sh && npm install 45 | ``` 46 | - test: 47 | ```bash 48 | bash bin/env_setup && . $HOME/.nvm/nvm.sh && npm test 49 | ``` 50 | -------------------------------------------------------------------------------- /temperature-basic/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "temperatureConverter": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/temperatureConverter", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": true, 26 | "assets": [ 27 | "src/favicon.ico", 28 | "src/assets", 29 | { 30 | "glob": "**/*", 31 | "input": "./node_modules/h8k-design/dist/assets/", 32 | "output": "./assets/" 33 | } 34 | ], 35 | "styles": [ 36 | "src/styles.scss" 37 | ], 38 | "scripts": [] 39 | }, 40 | "configurations": { 41 | "production": { 42 | "fileReplacements": [ 43 | { 44 | "replace": "src/environments/environment.ts", 45 | "with": "src/environments/environment.prod.ts" 46 | } 47 | ], 48 | "optimization": true, 49 | "outputHashing": "all", 50 | "sourceMap": false, 51 | "extractCss": true, 52 | "namedChunks": false, 53 | "extractLicenses": true, 54 | "vendorChunk": false, 55 | "buildOptimizer": true, 56 | "budgets": [ 57 | { 58 | "type": "initial", 59 | "maximumWarning": "2mb", 60 | "maximumError": "5mb" 61 | }, 62 | { 63 | "type": "anyComponentStyle", 64 | "maximumWarning": "6kb", 65 | "maximumError": "10kb" 66 | } 67 | ] 68 | } 69 | } 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "options": { 74 | "browserTarget": "temperatureConverter:build" 75 | }, 76 | "configurations": { 77 | "production": { 78 | "browserTarget": "temperatureConverter:build:production" 79 | } 80 | } 81 | }, 82 | "extract-i18n": { 83 | "builder": "@angular-devkit/build-angular:extract-i18n", 84 | "options": { 85 | "browserTarget": "temperatureConverter:build" 86 | } 87 | }, 88 | "test": { 89 | "builder": "@angular-devkit/build-angular:karma", 90 | "options": { 91 | "main": "src/test.ts", 92 | "polyfills": "src/polyfills.ts", 93 | "tsConfig": "tsconfig.spec.json", 94 | "karmaConfig": "karma.conf.js", 95 | "assets": [ 96 | "src/favicon.ico", 97 | "src/assets" 98 | ], 99 | "styles": [ 100 | "src/styles.scss" 101 | ], 102 | "scripts": [] 103 | } 104 | }, 105 | "e2e": { 106 | "builder": "@angular-devkit/build-angular:protractor", 107 | "options": { 108 | "protractorConfig": "e2e/protractor.conf.js", 109 | "devServerTarget": "temperatureConverter:serve" 110 | }, 111 | "configurations": { 112 | "production": { 113 | "devServerTarget": "temperatureConverter:serve:production" 114 | } 115 | } 116 | } 117 | } 118 | } 119 | }, 120 | "defaultProject": "temperatureConverter", 121 | "cli": { 122 | "analytics": "013a14ed-d2b0-402c-88f7-e52b13af2b80" 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /temperature-basic/bin/env_setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash 4 | export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" 5 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm 6 | nvm install v12 7 | nvm use v12 8 | echo "install complete" 9 | exit 0 10 | -------------------------------------------------------------------------------- /temperature-basic/exam.txt: -------------------------------------------------------------------------------- 1 | Create a Temperature Converter component, as shown below: 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | The component should have the following functionalities: 10 | 11 | 12 | 13 | It has 2 input number fields. The first is for a Celsius value, and the second is for a Fahrenheit value. 14 | 15 | 16 | Initially, both fields are empty. 17 | 18 | 19 | As a value is typed into the Celsius field, convert it to Fahrenheit and show it in the Fahrenheit field. Use the formula F = C*9/5 + 32 for conversion. In case of decimals, show up to 1 decimal value. 20 | 21 | 22 | As a value is typed into the Fahrenheit field, convert it to Celsius and show it in the Celsius field. Use the formula C = (F − 32) × 5/9 for conversion. In case of decimals, show up to 1 decimal value. 23 | 24 | 25 | 26 | 27 | 28 | The following data-test-id attributes are required in the component for the tests to pass: 29 | 30 | 31 | 32 | The Celsius input should have the data-test-id attribute 'celsius-input'. 33 | 34 | 35 | The Fahrenheit input should have the data-test-id attribute 'fahrenheit-input'. 36 | 37 | 38 | 39 | 40 | 41 | Please note that the component has the above data-test-id attributes for test cases and certain classes and ids for rendering purposes. It is advised not to change them. 42 | -------------------------------------------------------------------------------- /temperature-basic/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('@angular-devkit/build-angular/plugins/karma'), 12 | require('karma-mocha-reporter'), 13 | require('karma-junit-reporter') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | reporters: ['mocha', 'junit'], 19 | port: 9876, 20 | colors: true, 21 | logLevel: config.LOG_INFO, 22 | autoWatch: true, 23 | browsers: ['ChromeHeadless'], 24 | singleRun: true, 25 | restartOnFileChange: true, 26 | junitReporter: { 27 | useBrowserName: false, 28 | outputFile: 'unit.xml', 29 | suite: 'unit' 30 | } 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /temperature-basic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "temperature-converter", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "prestart": "npm install", 7 | "pretest": "npm install", 8 | "start": "ng serve --host 0.0.0.0 --port 8000 --disable-host-check", 9 | "build": "ng build", 10 | "test": "ng test" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/common": "~10.0.4", 15 | "@angular/compiler": "~10.0.4", 16 | "@angular/core": "~10.0.4", 17 | "@angular/forms": "~10.0.4", 18 | "@angular/platform-browser": "~10.0.4", 19 | "@angular/platform-browser-dynamic": "~10.0.4", 20 | "@angular/router": "^10.0.4", 21 | "h8k-components": "^1.0.0", 22 | "h8k-design": "^1.0.15", 23 | "rxjs": "~6.5.4", 24 | "tslib": "^1.10.0", 25 | "zone.js": "~0.10.2" 26 | }, 27 | "devDependencies": { 28 | "@angular-devkit/build-angular": "~0.1000.3", 29 | "@angular/cli": "~10.0.4", 30 | "@angular/compiler-cli": "~10.0.4", 31 | "@angular/language-service": "~10.0.4", 32 | "@types/node": "^12.11.1", 33 | "@types/jasmine": "~3.5.0", 34 | "@types/jasminewd2": "~2.0.3", 35 | "codelyzer": "^5.1.2", 36 | "jasmine-core": "~3.5.0", 37 | "jasmine-spec-reporter": "~4.2.1", 38 | "karma-junit-reporter": "^2.0.1", 39 | "karma": "~4.3.0", 40 | "karma-mocha-reporter": "^2.2.5", 41 | "mocha": "~7.1.0", 42 | "karma-chrome-launcher": "~3.1.0", 43 | "karma-jasmine": "~2.0.1", 44 | "ts-node": "~8.3.0", 45 | "typescript": "~3.9.5" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /temperature-basic/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /temperature-basic/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /temperature-basic/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed, async} from '@angular/core/testing'; 2 | import {AppComponent} from './app.component'; 3 | import {FormsModule} from '@angular/forms'; 4 | import {RouterTestingModule} from '@angular/router/testing' 5 | 6 | describe('AppComponent', () => { 7 | beforeEach(async(() => { 8 | TestBed.configureTestingModule({ 9 | imports: [ 10 | RouterTestingModule, 11 | FormsModule 12 | ], 13 | declarations: [ 14 | AppComponent 15 | ], 16 | }).compileComponents(); 17 | })); 18 | }); 19 | -------------------------------------------------------------------------------- /temperature-basic/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'Temperature Converter'; 10 | } 11 | -------------------------------------------------------------------------------- /temperature-basic/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from "@angular/platform-browser"; 2 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"; 3 | import { FormsModule, ReactiveFormsModule } from "@angular/forms"; 4 | import { AppComponent } from "./app.component"; 5 | 6 | import { TemperatureConverter } from "./temperatureConverter/temperatureConverter.component"; 7 | import { RouterModule } from "@angular/router"; 8 | import { RouterTestingModule } from "@angular/router/testing"; 9 | 10 | @NgModule({ 11 | declarations: [AppComponent, TemperatureConverter], 12 | imports: [ 13 | BrowserModule, 14 | FormsModule, 15 | RouterTestingModule, 16 | RouterModule.forRoot([{ path: "", component: TemperatureConverter }]), 17 | ], 18 | exports: [RouterModule], 19 | providers: [], 20 | bootstrap: [AppComponent], 21 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 22 | }) 23 | export class AppModule {} 24 | -------------------------------------------------------------------------------- /temperature-basic/src/app/temperatureConverter/temperatureConverter.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 11 |
12 | 13 |
14 | 15 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /temperature-basic/src/app/temperatureConverter/temperatureConverter.component.scss: -------------------------------------------------------------------------------- 1 | section { 2 | padding-top: 20px; 3 | width: 300px; 4 | } 5 | -------------------------------------------------------------------------------- /temperature-basic/src/app/temperatureConverter/temperatureConverter.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from "@angular/core/testing"; 2 | import { TemperatureConverter } from "./temperatureConverter.component"; 3 | import { RouterTestingModule } from "@angular/router/testing"; 4 | import { FormsModule } from "@angular/forms"; 5 | import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core"; 6 | 7 | fdescribe("TemperatureConverter", () => { 8 | let component: TemperatureConverter; 9 | let fixture: ComponentFixture; 10 | let compiled; 11 | let celsiusInput; 12 | let fahrenheitInput; 13 | 14 | const pushCelsiusValue = async (value) => { 15 | celsiusInput.value = value; 16 | celsiusInput.dispatchEvent(new Event("change")); 17 | celsiusInput.dispatchEvent(new Event("input")); 18 | await fixture.whenStable(); 19 | await fixture.detectChanges(); 20 | }; 21 | 22 | const pushFahrenheitValue = async (value) => { 23 | fahrenheitInput.value = value; 24 | fahrenheitInput.dispatchEvent(new Event("change")); 25 | fahrenheitInput.dispatchEvent(new Event("input")); 26 | await fixture.whenStable(); 27 | await fixture.detectChanges(); 28 | }; 29 | 30 | const getByTestId = (testId: string) => { 31 | return compiled.querySelector(`[data-test-id="${testId}"]`); 32 | }; 33 | 34 | beforeEach(async(() => { 35 | TestBed.configureTestingModule({ 36 | imports: [RouterTestingModule, FormsModule], 37 | declarations: [TemperatureConverter], 38 | schemas: [CUSTOM_ELEMENTS_SCHEMA], 39 | }).compileComponents(); 40 | })); 41 | 42 | beforeEach(() => { 43 | fixture = TestBed.createComponent(TemperatureConverter); 44 | fixture.autoDetectChanges(true); 45 | compiled = fixture.debugElement.nativeElement; 46 | component = fixture.componentInstance; 47 | celsiusInput = getByTestId("celsius-input"); 48 | fahrenheitInput = getByTestId("fahrenheit-input"); 49 | fixture.detectChanges(); 50 | }); 51 | 52 | it("Typing value in Celsius field gets correct Fahrenheit value", async () => { 53 | await pushCelsiusValue(500); 54 | fahrenheitInput = getByTestId("fahrenheit-input"); 55 | expect(Number(fahrenheitInput.value)).toEqual(932); 56 | }); 57 | 58 | it("Typing value in Celsius field gets correct Fahrenheit value upto 1 decimal values", async () => { 59 | await pushCelsiusValue(32); 60 | fahrenheitInput = getByTestId("fahrenheit-input"); 61 | expect(Number(fahrenheitInput.value)).toEqual(89.6); 62 | }); 63 | 64 | it("Typing value in Fahrenheit field gets correct Celsius value", async () => { 65 | await pushFahrenheitValue(932); 66 | celsiusInput = getByTestId("celsius-input"); 67 | expect(Number(celsiusInput.value)).toEqual(500); 68 | }); 69 | 70 | it("Typing value in Fahrenheit field gets correct Celsius value upto 1 decimal values", async () => { 71 | await pushFahrenheitValue(100); 72 | celsiusInput = getByTestId("celsius-input"); 73 | expect(Number(celsiusInput.value)).toEqual(37.8); 74 | }); 75 | 76 | it("Perform series of actions", async () => { 77 | await pushFahrenheitValue(10); 78 | celsiusInput = getByTestId("celsius-input"); 79 | expect(Number(celsiusInput.value)).toEqual(-12.2); 80 | 81 | await pushCelsiusValue(10); 82 | fahrenheitInput = getByTestId("fahrenheit-input"); 83 | expect(Number(fahrenheitInput.value)).toEqual(50); 84 | 85 | await pushFahrenheitValue(200); 86 | celsiusInput = getByTestId("celsius-input"); 87 | expect(Number(celsiusInput.value)).toEqual(93.3); 88 | 89 | await pushCelsiusValue(248); 90 | fahrenheitInput = getByTestId("fahrenheit-input"); 91 | expect(Number(fahrenheitInput.value)).toEqual(478.4); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /temperature-basic/src/app/temperatureConverter/temperatureConverter.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "temperature-converter", 5 | templateUrl: "./temperatureConverter.component.html", 6 | styleUrls: ["./temperatureConverter.component.scss"], 7 | }) 8 | export class TemperatureConverter implements OnInit { 9 | c = ""; 10 | f = ""; 11 | constructor() {} 12 | 13 | ngOnInit() {} 14 | 15 | onChange(value: string | null, type: "c" | "f") { 16 | if (value === null) { 17 | this.c = ""; 18 | this.f = ""; 19 | return; 20 | } 21 | 22 | const temperature = Number(value); 23 | if (type === "c") { 24 | this.f = ((temperature * 9) / 5 + 32).toFixed(1); 25 | } else { 26 | this.c = (((temperature - 32) * 5) / 9).toFixed(1); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /temperature-basic/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | .gitkeep 2 | -------------------------------------------------------------------------------- /temperature-basic/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /temperature-basic/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | -------------------------------------------------------------------------------- /temperature-basic/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashket980/HackerRank-Angular-basic/49f57121bef3e2219750f7105977864c0639cdf2/temperature-basic/src/favicon.ico -------------------------------------------------------------------------------- /temperature-basic/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Temperature Converter 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /temperature-basic/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import {applyPolyfills, defineCustomElements} from "h8k-components/loader"; 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | 14 | applyPolyfills() 15 | .then(() => { 16 | defineCustomElements() 17 | }) 18 | -------------------------------------------------------------------------------- /temperature-basic/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /temperature-basic/src/styles.scss: -------------------------------------------------------------------------------- 1 | @import "node_modules/h8k-design/lib/index"; 2 | 3 | body { 4 | margin: 0; 5 | } 6 | -------------------------------------------------------------------------------- /temperature-basic/src/text.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /temperature-basic/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /temperature-basic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "allowSyntheticDefaultImports": true, 14 | "target": "es2015", 15 | "lib": [ 16 | "es2018", 17 | "dom" 18 | ] 19 | }, 20 | "angularCompilerOptions": { 21 | "fullTemplateTypeCheck": true, 22 | "strictInjectionParameters": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /temperature-basic/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /weather-details/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /weather-details/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /weather-details/README.md: -------------------------------------------------------------------------------- 1 | # Angular: Weather Component 2 | 3 | ## Environment 4 | 5 | - Angular CLI Version: 10.0.4 6 | - Angular Core Version: 10.0.4 7 | - Node Version: 12.18.3 8 | - Default Port: 8000 9 | 10 | ## Application Demo: 11 | 12 | ![](https://hrcdn.net/s3_pub/istreet-assets/aiYyB8bIMufQ00lpPduPbQ/weather-component.gif) 13 | 14 | ## Functionality Requirements 15 | 16 | - An array of objects is passed as a prop to the component, where each object is a weather record for a single city. The object has 4 properties: 17 | 1. name: The name of the city. [STRING] 18 | 2. temperature: The temperature in the city. [STRING] 19 | 3. wind: The wind in the city. [STRING] 20 | 4. humidity: The humidity in the cit.y [STRING] 21 | 22 | - There is an input field for the city name where the user can type the name of a city to search the weather data for. (The city name is case-insensitive.) 23 | 24 | - If data exists for the typed input, render the weather details `
` as below, inside `
`. 25 | 1. `{temperature}`, where {temperature} is the value from the weather record. 26 | 2. `
Wind: {wind}
`, where {wind} is the value from the weather record. 27 | 3. `
Humidity: {humidity}
`, where {humidity} is the value from the weather record. 28 | 29 | - If no data exists for the typed input, do not render the weather details `
`, but instead render `
No Results Found
`. 30 | 31 | - At component render, since nothing is typed, do not render above 2 divs. 32 | 33 | ## Testing Requirements 34 | 35 | - The city name input should have the data-test-id attribute 'app-input'. 36 | 37 | - The `
` containing weather details should have the data-test-id attribute 'weather-details'. 38 | 39 | - The `` containing the temperature should have the data-test-id attribute 'output-temperature'. 40 | 41 | - The `
` containing the wind information should have the data-test-id attribute 'output-wind'. 42 | 43 | - The `
` containing the humidity information should have the data-test-id attribute 'output-humidity'. 44 | 45 | - The 'No Results Found' `
` should have the data-test-id attribute 'no-results'. 46 | 47 | 48 | ## Project Specifications 49 | 50 | **Read-only Files** 51 | - src/app/weatherDetails/weatherDetails.component.spec.ts 52 | - src/app/app.component.spec.ts 53 | - src/app/app.component.ts 54 | - src/app/app.module.ts 55 | 56 | **Commands** 57 | - run: 58 | ```bash 59 | bash bin/env_setup && . $HOME/.nvm/nvm.sh && npm start 60 | ``` 61 | - install: 62 | ```bash 63 | bash bin/env_setup && . $HOME/.nvm/nvm.sh && npm install 64 | ``` 65 | - test: 66 | ```bash 67 | bash bin/env_setup && . $HOME/.nvm/nvm.sh && npm test 68 | ``` 69 | -------------------------------------------------------------------------------- /weather-details/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "weatherDetails": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/weatherDetails", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "tsconfig.app.json", 25 | "aot": true, 26 | "assets": [ 27 | "src/favicon.ico", 28 | "src/assets", 29 | { 30 | "glob": "**/*", 31 | "input": "./node_modules/h8k-design/dist/assets/", 32 | "output": "./assets/" 33 | } 34 | ], 35 | "styles": [ 36 | "src/styles.scss" 37 | ], 38 | "scripts": [] 39 | }, 40 | "configurations": { 41 | "production": { 42 | "fileReplacements": [ 43 | { 44 | "replace": "src/environments/environment.ts", 45 | "with": "src/environments/environment.prod.ts" 46 | } 47 | ], 48 | "optimization": true, 49 | "outputHashing": "all", 50 | "sourceMap": false, 51 | "extractCss": true, 52 | "namedChunks": false, 53 | "extractLicenses": true, 54 | "vendorChunk": false, 55 | "buildOptimizer": true, 56 | "budgets": [ 57 | { 58 | "type": "initial", 59 | "maximumWarning": "2mb", 60 | "maximumError": "5mb" 61 | }, 62 | { 63 | "type": "anyComponentStyle", 64 | "maximumWarning": "6kb", 65 | "maximumError": "10kb" 66 | } 67 | ] 68 | } 69 | } 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "options": { 74 | "browserTarget": "weatherDetails:build" 75 | }, 76 | "configurations": { 77 | "production": { 78 | "browserTarget": "weatherDetails:build:production" 79 | } 80 | } 81 | }, 82 | "extract-i18n": { 83 | "builder": "@angular-devkit/build-angular:extract-i18n", 84 | "options": { 85 | "browserTarget": "weatherDetails:build" 86 | } 87 | }, 88 | "test": { 89 | "builder": "@angular-devkit/build-angular:karma", 90 | "options": { 91 | "main": "src/test.ts", 92 | "polyfills": "src/polyfills.ts", 93 | "tsConfig": "tsconfig.spec.json", 94 | "karmaConfig": "karma.conf.js", 95 | "assets": [ 96 | "src/favicon.ico", 97 | "src/assets" 98 | ], 99 | "styles": [ 100 | "src/styles.scss" 101 | ], 102 | "scripts": [] 103 | } 104 | }, 105 | "e2e": { 106 | "builder": "@angular-devkit/build-angular:protractor", 107 | "options": { 108 | "protractorConfig": "e2e/protractor.conf.js", 109 | "devServerTarget": "weatherDetails:serve" 110 | }, 111 | "configurations": { 112 | "production": { 113 | "devServerTarget": "weatherDetails:serve:production" 114 | } 115 | } 116 | } 117 | } 118 | }}, 119 | "defaultProject": "weatherDetails" 120 | } 121 | -------------------------------------------------------------------------------- /weather-details/bin/env_setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash 4 | export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" 5 | [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm 6 | nvm install v12 7 | nvm use v12 8 | echo "install complete" 9 | exit 0 10 | -------------------------------------------------------------------------------- /weather-details/exam.txt: -------------------------------------------------------------------------------- 1 | Create a Weather Details component, as shown below: 2 | 3 | The component must have the following functionalities: 4 | 5 | An array of objects is passed as a prop to the component, where each object is a weather record for a single city. The object has 4 properties: 6 | - name: The name of the city. [STRING] 7 | - temperature: The temperature in the city. [STRING] 8 | - wind: The wind in the city. [STRING] 9 | - humidity: The humidity in the city. [STRING] 10 | 11 | 12 | There is an input field for the city name where the user can type the name of a city to search the weather data for. (The city name is case-insensitive.) 13 | 14 | If data exists for the typed input, render the weather details
as below, inside
. 15 | 16 | {temperature}, where {temperature} is the value from the weather record. 17 |
Wind: {wind}
, where {wind} is the value from the weather record. 18 |
Humidity: {humidity}
, where {humidity} is the value from the weather record. 19 | 20 | 21 | If no data exists for the typed input, do not render the weather details
, but instead render
No Results Found
. 22 | 23 | At component render, since nothing is typed, do not render the above two
elements ("weather-details" and "no-results"). 24 | 25 | The following data-test-id attributes are required in the component for the tests to pass: 26 | The city name input should have the data-test-id attribute 'app-input'. 27 | The
containing weather details should have the data-test-id attribute 'weather-details'. 28 | The containing the temperature should have the data-test-id attribute 'output-temperature'. 29 | The
containing the wind information should have the data-test-id attribute 'output-wind'. 30 | The
containing the humidity information should have the data-test-id attribute 'output-humidity'. 31 | The 'No Results Found'
should have the data-test-id attribute 'no-results'. 32 | 33 | Please note that components have the above data-test-id attributes for test cases and certain classes and ids for rendering purposes. It is advised not to change them. 34 | -------------------------------------------------------------------------------- /weather-details/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | 3 | // https://karma-runner.github.io/1.0/config/configuration-file.html 4 | 5 | 6 | module.exports = function (config) { 7 | config.set({ 8 | basePath: '', 9 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 10 | plugins: [ 11 | require('karma-jasmine'), 12 | require('karma-chrome-launcher'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | require('karma-mocha-reporter'), 15 | require('karma-junit-reporter') 16 | ], 17 | client: { 18 | clearContext: false // leave Jasmine Spec Runner output visible in browser 19 | }, 20 | reporters: ['mocha', 'junit'], 21 | port: 9876, 22 | colors: true, 23 | logLevel: config.LOG_INFO, 24 | autoWatch: true, 25 | browsers: ['ChromeHeadless'], 26 | singleRun: true, 27 | restartOnFileChange: true, 28 | junitReporter: { 29 | useBrowserName: false, 30 | outputFile: 'unit.xml', 31 | suite: 'unit' 32 | } 33 | }); 34 | }; 35 | -------------------------------------------------------------------------------- /weather-details/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weather-details", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "prestart": "npm install", 7 | "pretest": "npm install", 8 | "start": "ng serve --host 0.0.0.0 --port 8000 --disable-host-check", 9 | "build": "ng build", 10 | "test": "ng test" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/common": "~10.0.4", 15 | "@angular/compiler": "~10.0.4", 16 | "@angular/core": "~10.0.4", 17 | "@angular/forms": "~10.0.4", 18 | "@angular/platform-browser": "~10.0.4", 19 | "@angular/platform-browser-dynamic": "~10.0.4", 20 | "@angular/router": "^10.0.4", 21 | "h8k-components": "^1.0.0", 22 | "h8k-design": "^1.0.15", 23 | "bluebird": "^3.7.2", 24 | "rxjs": "~6.5.4", 25 | "tslib": "^1.10.0", 26 | "zone.js": "~0.10.2" 27 | }, 28 | "devDependencies": { 29 | "@angular-devkit/build-angular": "~0.1000.3", 30 | "@angular/cli": "~10.0.4", 31 | "@angular/compiler-cli": "~10.0.4", 32 | "@angular/language-service": "~10.0.4", 33 | "@types/node": "^12.11.1", 34 | "@types/jasmine": "~3.5.0", 35 | "@types/jasminewd2": "~2.0.3", 36 | "codelyzer": "^5.1.2", 37 | "jasmine-core": "~3.5.0", 38 | "jasmine-spec-reporter": "~4.2.1", 39 | "karma-junit-reporter": "^2.0.1", 40 | "karma": "~4.3.0", 41 | "karma-mocha-reporter": "^2.2.5", 42 | "mocha": "~7.1.0", 43 | "karma-chrome-launcher": "~3.1.0", 44 | "karma-jasmine": "~2.0.1", 45 | "ts-node": "~8.3.0", 46 | "typescript": "~3.9.5" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /weather-details/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | -------------------------------------------------------------------------------- /weather-details/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /weather-details/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed, async} from '@angular/core/testing'; 2 | import {AppComponent} from './app.component'; 3 | import {FormsModule} from '@angular/forms'; 4 | import {RouterTestingModule} from '@angular/router/testing' 5 | 6 | describe('AppComponent', () => { 7 | beforeEach(async(() => { 8 | TestBed.configureTestingModule({ 9 | imports: [ 10 | RouterTestingModule, 11 | FormsModule 12 | ], 13 | declarations: [ 14 | AppComponent 15 | ], 16 | }).compileComponents(); 17 | })); 18 | }); 19 | -------------------------------------------------------------------------------- /weather-details/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'] 7 | }) 8 | export class AppComponent { 9 | title = 'Weather Details'; 10 | 11 | weatherData = [ 12 | { 13 | "name": "San Jose", 14 | "temperature": "36º F", 15 | "wind": "31Kmph", 16 | "humidity": "66%" 17 | }, 18 | { 19 | "name": "Seattle", 20 | "temperature": "30º F", 21 | "wind": "4Kmph", 22 | "humidity": "9%" 23 | }, 24 | { 25 | "name": "New York", 26 | "temperature": "20º F", 27 | "wind": "8Kmph", 28 | "humidity": "61%" 29 | }, 30 | { 31 | "name": "Chicago", 32 | "temperature": "27º F", 33 | "wind": "35Kmph", 34 | "humidity": "2%" 35 | }, 36 | { 37 | "name": "Atlanta", 38 | "temperature": "22º F", 39 | "wind": "25Kmph", 40 | "humidity": "5%" 41 | }, 42 | { 43 | "name": "Austin", 44 | "temperature": "25º F", 45 | "wind": "1Kmph", 46 | "humidity": "5%" 47 | }, 48 | { 49 | "name": "Denver", 50 | "temperature": "30º F", 51 | "wind": "8Kmph", 52 | "humidity": "48%" 53 | } 54 | ]; 55 | } 56 | -------------------------------------------------------------------------------- /weather-details/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; 4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 5 | import { AppComponent } from './app.component'; 6 | 7 | import { WeatherDetails } from './weatherDetails/weatherDetails.component'; 8 | //Angular Router Module 9 | import { RouterModule, Router } from '@angular/router'; 10 | import {RouterTestingModule} from '@angular/router/testing'; 11 | 12 | @NgModule({ 13 | declarations: [ 14 | AppComponent, 15 | WeatherDetails 16 | ], 17 | imports: [ 18 | BrowserModule, 19 | FormsModule, 20 | RouterTestingModule, 21 | RouterModule.forRoot([ 22 | { path:'', component: WeatherDetails } 23 | ]) 24 | ], 25 | exports: [ 26 | RouterModule 27 | ], 28 | providers: [], 29 | bootstrap: [AppComponent], 30 | schemas : [CUSTOM_ELEMENTS_SCHEMA] 31 | }) 32 | export class AppModule { } 33 | -------------------------------------------------------------------------------- /weather-details/src/app/weatherDetails/weatherDetails.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 12 |
13 | 14 |
15 |
16 |
21 |
22 | 25 | {{ 26 | searchedData.temperature 27 | }} 28 |
29 |
30 |
31 | Wind: {{ searchedData.wind }} 32 |
33 |
34 | Humidity: {{ searchedData.humidity }} 35 |
36 |
37 |
38 |
43 | No Results Found 44 |
45 |
46 |
47 |
48 | -------------------------------------------------------------------------------- /weather-details/src/app/weatherDetails/weatherDetails.component.scss: -------------------------------------------------------------------------------- 1 | 2 | section { 3 | padding-top: 20px; 4 | } 5 | 6 | .card-text { 7 | width: 300px; 8 | } 9 | 10 | .weather-data { 11 | border: 1px solid#cbc9c9; 12 | padding: 50px; 13 | } 14 | 15 | .temperature { 16 | font-size: 35px; 17 | } 18 | -------------------------------------------------------------------------------- /weather-details/src/app/weatherDetails/weatherDetails.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {async, ComponentFixture, TestBed, tick} from '@angular/core/testing'; 2 | import {WeatherDetails} from './weatherDetails.component'; 3 | import {RouterTestingModule} from '@angular/router/testing'; 4 | import {FormsModule} from '@angular/forms'; 5 | let Bluebird = require('bluebird'); 6 | import {CUSTOM_ELEMENTS_SCHEMA} from "@angular/core"; 7 | 8 | describe('WeatherDetails', () => { 9 | let component: WeatherDetails; 10 | let fixture: ComponentFixture; 11 | let appInput; 12 | let weatherDetailsDiv; 13 | 14 | const pushValue = async (value, fixture) => { 15 | appInput.value = value; 16 | appInput.dispatchEvent(new Event('change')); 17 | appInput.dispatchEvent(new Event('input')); 18 | await fixture.whenStable(); 19 | }; 20 | 21 | const getByTestId = (testId: string, compiled) => { 22 | return compiled.querySelector(`[data-test-id="${testId}"]`); 23 | }; 24 | 25 | 26 | beforeEach(async(() => { 27 | TestBed 28 | .configureTestingModule({ 29 | imports: [ 30 | RouterTestingModule, 31 | FormsModule 32 | ], 33 | declarations: [WeatherDetails], 34 | schemas : [CUSTOM_ELEMENTS_SCHEMA] 35 | }) 36 | .compileComponents(); 37 | })); 38 | 39 | const factory = (weatherData) => { 40 | const fixture: ComponentFixture = TestBed.createComponent(WeatherDetails); 41 | const component: WeatherDetails = fixture.componentInstance; 42 | component.weatherData = weatherData; 43 | const compiled = fixture.debugElement.nativeElement; 44 | fixture.detectChanges(); 45 | return { 46 | fixture, 47 | component, 48 | compiled 49 | }; 50 | }; 51 | 52 | const weatherData = [ 53 | { 54 | "name": "Denver", 55 | "temperature": "36º F", 56 | "wind": "31Kmph", 57 | "humidity": "66%" 58 | }, 59 | { 60 | "name": "Dallas", 61 | "temperature": "3º F", 62 | "wind": "4Kmph", 63 | "humidity": "9%" 64 | }, 65 | { 66 | "name": "Madison", 67 | "temperature": "15º F", 68 | "wind": "8Kmph", 69 | "humidity": "61%" 70 | }, 71 | { 72 | "name": "Portland", 73 | "temperature": "27º F", 74 | "wind": "35Kmph", 75 | "humidity": "2%" 76 | }, 77 | { 78 | "name": "Austin", 79 | "temperature": "12º F", 80 | "wind": "25Kmph", 81 | "humidity": "5%" 82 | }, 83 | { 84 | "name": "Phoenix", 85 | "temperature": "15º F", 86 | "wind": "1Kmph", 87 | "humidity": "5%" 88 | }, 89 | { 90 | "name": "Boston", 91 | "temperature": "5º F", 92 | "wind": "8Kmph", 93 | "humidity": "48%" 94 | } 95 | ]; 96 | 97 | const cities = ['Dallas', 'Portland', 'boston', 'phoenix']; 98 | 99 | const nonExistingCities = ['Seattle', 'new york', 'florida']; 100 | 101 | it('Initial UI is rendered as expected', async () => { 102 | const {compiled, fixture} = factory(weatherData); 103 | await fixture.whenStable(); 104 | appInput = getByTestId('app-input', compiled); 105 | weatherDetailsDiv = getByTestId('weather-details', compiled); 106 | const noResultFoundDiv = getByTestId('no-results', compiled); 107 | 108 | expect(appInput.value).toBeFalsy(); 109 | expect(weatherDetailsDiv).toBeFalsy(); 110 | expect(noResultFoundDiv).toBeFalsy(); 111 | }); 112 | 113 | it('Test with existing cities in both upper and small case', async (done) => { 114 | const {compiled, fixture} = factory(weatherData); 115 | await fixture.whenStable(); 116 | 117 | appInput = getByTestId('app-input', compiled); 118 | 119 | Bluebird.each(cities, async (city) => { 120 | await pushValue(city, fixture); 121 | await fixture.detectChanges(); 122 | const output = weatherData.filter(e => e.name.toLowerCase() === city.toLowerCase())[0]; 123 | expect(getByTestId('output-temperature', compiled).innerHTML.trim()).toBe(output.temperature); 124 | expect(getByTestId('output-wind', compiled).innerHTML.trim()).toBe(`Wind: ${output.wind}`); 125 | expect(getByTestId('output-humidity', compiled).innerHTML.trim()).toBe(`Humidity: ${output.humidity}`); 126 | expect(getByTestId('no-results', compiled)).toBeFalsy(); 127 | }) 128 | .then(() => { 129 | done(); 130 | }) 131 | }); 132 | 133 | it('Test with non-existing cities', async (done) => { 134 | const {compiled, fixture} = factory(weatherData); 135 | await fixture.whenStable(); 136 | 137 | appInput = getByTestId('app-input', compiled); 138 | 139 | Bluebird.each(nonExistingCities, async (city) => { 140 | await pushValue(city, fixture); 141 | await fixture.detectChanges(); 142 | expect(getByTestId('weather-details', compiled)).toBeFalsy(); 143 | expect(getByTestId('no-results', compiled).innerHTML.trim()).toBe('No Results Found'); 144 | }) 145 | .then(() => { 146 | done(); 147 | }) 148 | }); 149 | 150 | it('Perform series of actions', async () => { 151 | const {compiled, fixture} = factory(weatherData); 152 | await fixture.whenStable(); 153 | 154 | appInput = getByTestId('app-input', compiled); 155 | 156 | await pushValue('dallas', fixture); 157 | await fixture.detectChanges(); 158 | expect(getByTestId('output-temperature', compiled).innerHTML.trim()).toBe('3º F'); 159 | expect(getByTestId('output-wind', compiled).innerHTML.trim()).toBe(`Wind: 4Kmph`); 160 | expect(getByTestId('output-humidity', compiled).innerHTML.trim()).toBe(`Humidity: 9%`); 161 | expect(getByTestId('no-results', compiled)).toBeFalsy(); 162 | 163 | await pushValue('seattle', fixture); 164 | await fixture.detectChanges(); 165 | expect(getByTestId('weather-details', compiled)).toBeFalsy(); 166 | expect(getByTestId('no-results', compiled).innerHTML.trim()).toBe('No Results Found'); 167 | 168 | await pushValue('', fixture); 169 | await fixture.detectChanges(); 170 | expect(getByTestId('weather-details', compiled)).toBeFalsy(); 171 | expect(getByTestId('no-results', compiled)).toBeFalsy(); 172 | 173 | await pushValue('Boston', fixture); 174 | await fixture.detectChanges(); 175 | expect(getByTestId('output-temperature', compiled).innerHTML.trim()).toBe('5º F'); 176 | expect(getByTestId('output-wind', compiled).innerHTML.trim()).toBe(`Wind: 8Kmph`); 177 | expect(getByTestId('output-humidity', compiled).innerHTML.trim()).toBe(`Humidity: 48%`); 178 | expect(getByTestId('no-results', compiled)).toBeFalsy(); 179 | }); 180 | }); 181 | -------------------------------------------------------------------------------- /weather-details/src/app/weatherDetails/weatherDetails.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from "@angular/core"; 2 | 3 | @Component({ 4 | selector: "weather-details", 5 | templateUrl: "./weatherDetails.component.html", 6 | styleUrls: ["./weatherDetails.component.scss"], 7 | }) 8 | export class WeatherDetails implements OnInit { 9 | @Input() weatherData: data[]; 10 | 11 | searchTerm = ""; 12 | searchedData?: data = undefined; 13 | 14 | ngOnInit() {} 15 | 16 | onChange(value: string | null) { 17 | this.searchedData = this.weatherData.find( 18 | ({ name }) => name.toLowerCase() === value.toLowerCase() 19 | ); 20 | } 21 | } 22 | 23 | interface data { 24 | name: string; 25 | temperature: string; 26 | wind: string; 27 | humidity: string; 28 | } 29 | -------------------------------------------------------------------------------- /weather-details/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /weather-details/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /weather-details/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | -------------------------------------------------------------------------------- /weather-details/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ashket980/HackerRank-Angular-basic/49f57121bef3e2219750f7105977864c0639cdf2/weather-details/src/favicon.ico -------------------------------------------------------------------------------- /weather-details/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Weather Details 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /weather-details/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import {applyPolyfills, defineCustomElements} from "h8k-components/loader"; 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | 14 | applyPolyfills() 15 | .then(() => { 16 | defineCustomElements() 17 | }) 18 | -------------------------------------------------------------------------------- /weather-details/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /weather-details/src/styles.scss: -------------------------------------------------------------------------------- 1 | @import "node_modules/h8k-design/lib/index"; 2 | 3 | body { 4 | margin: 0; 5 | } 6 | -------------------------------------------------------------------------------- /weather-details/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /weather-details/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /weather-details/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "allowSyntheticDefaultImports": true, 14 | "target": "es2015", 15 | "lib": [ 16 | "es2018", 17 | "dom" 18 | ] 19 | }, 20 | "angularCompilerOptions": { 21 | "fullTemplateTypeCheck": true, 22 | "strictInjectionParameters": true 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /weather-details/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | --------------------------------------------------------------------------------