{"id":21245820,"url":"https://github.com/wishtack/workshop-angular-testing","last_synced_at":"2025-03-15T04:44:00.795Z","repository":{"id":38688735,"uuid":"210818389","full_name":"wishtack/workshop-angular-testing","owner":"wishtack","description":"Angular testing workshop","archived":false,"fork":false,"pushed_at":"2023-01-07T10:04:13.000Z","size":2837,"stargazers_count":1,"open_issues_count":24,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-21T20:23:19.514Z","etag":null,"topics":["angular","testing","workshop"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wishtack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-25T10:31:03.000Z","updated_at":"2019-11-21T09:48:22.000Z","dependencies_parsed_at":"2023-02-06T21:15:45.302Z","dependency_job_id":null,"html_url":"https://github.com/wishtack/workshop-angular-testing","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wishtack%2Fworkshop-angular-testing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wishtack%2Fworkshop-angular-testing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wishtack%2Fworkshop-angular-testing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wishtack%2Fworkshop-angular-testing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wishtack","download_url":"https://codeload.github.com/wishtack/workshop-angular-testing/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243685527,"owners_count":20330980,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","testing","workshop"],"created_at":"2024-11-21T02:00:29.682Z","updated_at":"2025-03-15T04:44:00.775Z","avatar_url":"https://github.com/wishtack.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Angular Testing Workshop\n\nThis is an angular unit-testing workshop by [Younes](https://twitter.com/yjaaidi) from [Wishtack](https://wishtack.io) and we can keep in touch here:\n\n- ℹ️ [wishtack.io](https://wishtack.io)\n- 📺 [marmicode.fr](https://marmicode.fr)\n- 🐦 [@yjaaidi](https://twitter.com/yjaaidi)\n- 💻 [github/wishtack](https://github.com/wishtack)\n\nIt is made to run on codesandbox.\n\n\u003cp align=\"center\"\u003e\n    \u003cimg src=\"https://github.com/wishtack/codesandbox-angular-testing/raw/master/screenshot.png\" alt=\"Codesandbox Angular Testing\"\u003e\n\u003c/p\u003e\n\n# Workshop guide\n\n## 0. The skeleton\n\n[Click here to open the skeleton on Codesandbox](https://codesandbox.io/s/github/wishtack/workshop-angular-testing/tree/0-skeleton).\n\n## 1. Isolated testing `\u003capp-sandwich-search\u003e`\n\nLet’s start with a presentational component like `\u003capp-sandwich-search\u003e`\n\n### 1.1. Create the component\n\n```sh\nyarn ng g @wishtack/schematics:scam sandwich-search\n```\n\n### 1.2. Add empty specs to share intention\n\n```js\nxit('🚧 should search and display sandwiches', () =\u003e {\n  throw new Error('🚧 work in progress!');\n});\n```\n\n### 1.3. Describe the test with comments\n\n```\n// @todo create the component with…\n// @todo check this and that\n```\n\n### 1.4. 🎁 It's time for a sandwich 🍔\n\n```typescript\nexport class Sandwich {\n  id: string;\n  name: string;\n  price: number;\n\n  constructor(args: Partial\u003cSandwich\u003e = {}) {\n    this.id = args.id;\n    this.name = args.name;\n    this.price = args.price;\n  }\n}\n```\n\n### 1.5. Use `of` function to create an observable from synchronous source \n\n```js\nconst data$ = of(42)\ndata$.subscribe(console.log); // 42\n```\n\n### 1.6. Create the sandwich search \u0026 cart service\n\n… and let’s skip tests for now\n```sh\nyarn ng g service sandwich-search/sandwich-search —skipTests\nyarn ng g service cart/cart —skipTests\n```\n\n### 1.7. Implement the test and use IDE to generate the methods with the right signature\nTop down approach helps with generation and enforces good design.\nStart with the usage and not the implementation or interface.\n\n### 1.8. Enable the test by replacing `xit` with `it`... and make it work\n\n🛑🤔 [OPEN SOLUTION](https://codesandbox.io/s/github/wishtack/workshop-angular-testing/tree/1-isolated-testing-sandwich-search) \n\n## 2. Isolated testing `\u003capp-sandwich-search\u003e` with spies\n\n```js\nclass FavoriteColorService {\n  getFavoriteColor(userId) {\n    ...\n  }\n}\n\nfunction getCurrentUserFavoriteColor() {\n  return getFavoriteColor(currentUser.id);\n}\n\nit('...', () =\u003e {\n\n  const favoriteColorService = new FavoriteColorService();\n\n  spyOn(favoriteColorService, 'getFavoriteColor').and.returnValue('RED');\n\n  expect(getCurrentUserFavoriteColor()); // 'RED'\n\n  // ⚠️ remember to check that the spy has been called with the right parameters\n  expect(favoriteColorService.getFavoriteColor).toHaveBeenCalledWith('FOO'); // FAIL! Was called with `undefined` instead of FOO\n\n});\n```\n\n🛑🤔 [OPEN SOLUTION](https://codesandbox.io/s/github/wishtack/workshop-angular-testing/tree/2-isolated-testing-sandwich-search-with-spies)\n\n## 3. Dom testing `\u003capp-sandwich-list\u003e`\n\n### 3.1. Create the `\u003capp-sandwich-list\u003e` component\n```sh\nyarn ng g @wishtack/schematics:scam sandwich-list\n```\n\n### 3.2. Check that sandwiches are displayed by querying the view\n```js\nfixture.debugElement.queryAll(By.css('…'));\n```\n\n### 3.3. Remember to trigger the change detection when needed\n```js\nfixture.detectChanges();\n```\n\n### 3.4. Use `data-role` attribute to query elements\n```html\n\u003cbutton data-role=\"destroy-planet-button\"\u003eDESTROY PLANET\u003c/button\u003e\n```\n\n```js\nexpect(fixture.debugEment.query(By.css('[data=\"destroy-planet-button\"]'))).toBeNull(); // 😰\n```\n\n🛑🤔 [OPEN SOLUTION](https://codesandbox.io/s/github/wishtack/workshop-angular-testing/tree/3-dom-testing-sandwich-list)\n\n## 4. Dom testing events\n\n### 4.1. Trigger a click\n```js\nconst clickEvent = {};\nfixture.debugElement.query(...).triggerEventHandler('click', clickEvent);\n```\n\n### 4.2. Subscribe to component's output\n\n😉 `EventEmitter` is a `Subject` which is an `Observable`, so you can subscribe to the output.\n\n🛑🤔 [OPEN SOLUTION](https://codesandbox.io/s/github/wishtack/workshop-angular-testing/tree/4-dom-testing-sandwich-list-events)\n\n## 5. Shallow testing \n\n### 5.1. Ignore unknown elements\n```js\nTestBed.configureTestingModule({\n  declarations: [DestroyPlanetComponent],\n  schemas: [CUSTOM_ELEMENTS_SCHEMA]\n}).compileComponents();\n```\n\n### 5.2. Inject services\n```js\nlet myService: MyService;\nbeforeEach(() =\u003e myService = TestBed.inject(MyService)); // Since Angular 9\nbeforeEach(() =\u003e myService = TestBed.get(MyService)) // Before Angular 9\n```\n\n🛑🤔 [OPEN SOLUTION](https://codesandbox.io/s/github/wishtack/workshop-angular-testing/tree/5-shallow-testing-sandwich-search)\n\n# Known issues with Codesandbox\n🐞 There are some memory limitations on codesandbox that can make karma crash.\nIf you want to use karma and you don't need to run the app simultaneously, then you can simply replace `\"start\": \"ng serve...\"` by `\"start\": \"ng test\"`.\nCodesandbox will run karma instead of the app which will reduce memory usage.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwishtack%2Fworkshop-angular-testing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwishtack%2Fworkshop-angular-testing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwishtack%2Fworkshop-angular-testing/lists"}