{"id":13495588,"url":"https://github.com/getsaf/shallow-render","last_synced_at":"2025-03-28T16:32:57.314Z","repository":{"id":29142903,"uuid":"120038299","full_name":"getsaf/shallow-render","owner":"getsaf","description":"Angular testing made easy with shallow rendering and easy mocking. https://getsaf.github.io/shallow-render","archived":false,"fork":false,"pushed_at":"2025-03-10T00:06:50.000Z","size":2669,"stargazers_count":273,"open_issues_count":2,"forks_count":27,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-22T16:47:02.530Z","etag":null,"topics":["angular","enzyme","mock","testbed","testing","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/getsaf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-02T22:29:35.000Z","updated_at":"2025-03-10T00:05:20.000Z","dependencies_parsed_at":"2023-10-14T18:24:52.774Z","dependency_job_id":"a18a187a-5d3a-4428-9f84-66f8524faaf5","html_url":"https://github.com/getsaf/shallow-render","commit_stats":{"total_commits":345,"total_committers":17,"mean_commits":"20.294117647058822","dds":0.5246376811594202,"last_synced_commit":"fa016f20fbcbeff593e73b43168cae714564df98"},"previous_names":[],"tags_count":109,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsaf%2Fshallow-render","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsaf%2Fshallow-render/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsaf%2Fshallow-render/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/getsaf%2Fshallow-render/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/getsaf","download_url":"https://codeload.github.com/getsaf/shallow-render/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246063091,"owners_count":20717742,"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","enzyme","mock","testbed","testing","typescript"],"created_at":"2024-07-31T19:01:36.217Z","updated_at":"2025-03-28T16:32:57.264Z","avatar_url":"https://github.com/getsaf.png","language":"TypeScript","readme":"# shallow-render\n\n[![CircleCI](https://circleci.com/gh/getsaf/shallow-render.svg?style=svg)](https://circleci.com/gh/getsaf/shallow-render)\n[![npm version](https://badge.fury.io/js/shallow-render.svg)](https://www.npmjs.com/package/shallow-render)\n\nAngular testing made easy with shallow rendering and easy mocking.\n\n---\n\n# Looking For Help Maintaining This Library!\n\nHey all, I do plan on continuing to update this library as Angular provides updates. This is not easy for me to do as I don't work with Angular in my current job.\n\nAny additonal support would be very appreciated! Please reach out if you want to be a help!\n\n## Docs\n\n- [API Docs](https://getsaf.github.io/shallow-render)\n- [Example Tests](https://github.com/getsaf/shallow-render/tree/master/lib/examples)\n- [Release Notes](https://github.com/getsaf/shallow-render/releases)\n\n## Schematics\n\n- [Angular Schematics](https://github.com/mihalcan/shallow-render-shematics) (thanks @mihalcan!)\n\n## Articles\n\n- [Testing Angular Components With shallow-render](https://medium.com/@getsaf/testing-angular-components-with-shallow-render-9334d16dc2e3?source=friends_link\u0026sk=5c72c2bf4ce91da656916dc680f8b1cf)\n- [Advanced shallow-render Testing](https://medium.com/@getsaf/advanced-shallow-render-testing-for-angular-components-452ce74d5f88?source=friends_link\u0026sk=91d48511b60871c7b34b1bbb231ce1a5)\n- [Why Shallow Rendering is Important](https://medium.com/@getsaf/why-shallow-rendering-is-import-in-angular-unit-tests-84569d571b72?source=friends_link\u0026sk=4576570c948a531036cc8fe9e2dc9a19)\n\n## Angular Version Support\n\n| Angular | shallow-render |\n| ------- | -------------- |\n| 19x     | 19x            |\n| 18x     | 18x            |\n| 17x     | 17x            |\n| 16x     | 16x            |\n| 15x     | 15x            |\n| 14x     | 14x            |\n| 13x     | 13x            |\n| 12x     | 12x            |\n| 11x     | 11x            |\n| 10x     | 10x            |\n| 9x      | 9x             |\n| 6x-8x   | 8x             |\n| 5x      | \u003c= 7.2.0       |\n\n## Super Simple Tests\n\n```typescript\ndescribe('ColorLinkComponent', () =\u003e {\n  let shallow: Shallow\u003cColorLinkComponent\u003e;\n\n  beforeEach(() =\u003e {\n    shallow = new Shallow(ColorLinkComponent, MyModule);\n  });\n\n  it('renders a link with the name of the color', async () =\u003e {\n    const { find } = await shallow.render({ bind: { color: 'Blue' } });\n    // or shallow.render(`\u003ccolor-link color=\"Blue\"\u003e\u003c/color-link\u003e`);\n\n    expect(find('a').nativeElement.textContent).toBe('Blue');\n  });\n\n  it('emits color when clicked', async () =\u003e {\n    const { element, outputs } = await shallow.render({ bind: { color: 'Red' } });\n    element.click();\n\n    expect(outputs.handleClick.emit).toHaveBeenCalledWith('Red');\n  });\n});\n```\n\n## The problem\n\nTesting in Angular is **HARD**. TestBed is powerful but its use in component specs ends with lots of duplication.\n\nHere's a standard TestBed spec for a component that uses a few other components, a directive and a pipe and handles click events:\n\n```typescript\ndescribe('MyComponent', () =\u003e {\n  beforeEach(async =\u003e {\n    return TestBed.configureTestModule({\n      imports: [SomeModuleWithDependencies],\n      declarations: [\n        TestHostComponent,\n        MyComponent, // \u003c-- All I want to do is test this!!\n        // We either must list all our dependencies here\n        // -- OR --\n        // Use NO_ERRORS_SCHEMA which allows any HTML to be used\n        // even if it is invalid!\n        ButtonComponent,\n        LinkComponent,\n        FooDirective,\n        BarPipe,\n      ],\n      providers: [MyService],\n    })\n      .compileComponents()\n      .then(() =\u003e {\n        let myService = TestBed.get(MyService); // Not type safe\n        spyOn(myService, 'foo').and.returnValue('mocked foo');\n      });\n  });\n\n  it('renders a link with the provided label text', () =\u003e {\n    const fixture = TestBed.createComponent(TestHostComponent);\n    fixture.componentInstance.labelText = 'my text';\n    fixture.detectChanges();\n    const link = fixture.debugElement.query(By.css('a'));\n\n    expect(a.nativeElement.textContent).toBe('my text');\n  });\n\n  it('sends \"foo\" to bound click events', () =\u003e {\n    const fixture = TestBed.createComponent(TestHostComponent);\n    spyOn(fixture.componentInstance, 'handleClick');\n    fixture.detectChanges();\n    const myComponentElement = fixture.debugElement.query(By.directive(MyComponent));\n    myComponentElement.click();\n\n    expect(fixture.componentInstance.handleClick).toHaveBeenCalledWith('foo');\n  });\n});\n\n@Component({\n  template: '\u003cmy-component [linkText]=\"linkText\" (click)=\"handleClick($event)\"\u003e\u003c/my-component\u003e',\n})\nclass TestHostComponent {\n  linkLabel: string;\n  handleClick() {}\n}\n```\n\nWhew!!! That was a lot of boilerplate. Here's just some of the issues:\n\n- Our TestBed module looks very similar if not identical to the `NgModule` I've probably already added `MyComponent` too. Total module duplication.\n- Since I've duplicated my module in my spec, I'm not actually sure the real module was setup correctly.\n- I've used REAL components and services in my spec which means I have not isolated the component I'm interested in testing.\n  - This also means I have to follow, and provide all the dependencies of those real components to the `TestBed` module.\n- I had to create a `TestHostComponent` so I could pass bindings into my actual component.\n- My `TestBed` boilerplate code-length exceeded my actual test code-length.\n\n## The Solution\n\nWe should mock everything we can except for the component in test and that should be **EASY**. Our modules already define the environment in which our components live. They should be _reused_, not _rebuilt_ in our specs.\n\nHere's the same specs using `shallow-render`:\n\n```typescript\ndescribe('MyComponent', () =\u003e {\n  let shallow: Shallow\u003cMyComponent\u003e;\n\n  beforeEach(() =\u003e {\n    shallow = new Shallow(MyComponent, MyModule);\n  });\n\n  it('renders a link with the provided label text', async () =\u003e {\n    const { find } = await shallow.render({ bind: { linkText: 'my text' } });\n    // or shallow.render(`\u003cmy-component linkText=\"my text\"\u003e\u003c/my-component\u003e`);\n\n    expect(find('a').nativeElement.textContent).toBe('my text');\n  });\n\n  it('sends \"foo\" to bound click events', async () =\u003e {\n    const { element, outputs } = await shallow.render();\n    element.click();\n\n    expect(outputs.handleClick).toHaveBeenCalledWith('foo');\n  });\n});\n```\n\nHere's the difference:\n\n- Reuses (and verifies) `MyModule` contains your component and all its dependencies.\n- All components inside `MyModule` are mocked. This is what makes the rendering \"shallow\".\n- The tests have much less boilerplate which makes the specs easier to follow.\n- The HTML used to render the component is IN THE SPEC and easy to find.\n  - This means specs now double examples of how to use your component.\n","funding_links":[],"categories":["Testing","TypeScript"],"sub_categories":["Helpers"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetsaf%2Fshallow-render","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgetsaf%2Fshallow-render","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgetsaf%2Fshallow-render/lists"}