Skip to content

How can I use @Output communication in my test integration? #304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jadir-junior opened this issue Jun 30, 2022 · 10 comments · Fixed by #305
Closed

How can I use @Output communication in my test integration? #304

jadir-junior opened this issue Jun 30, 2022 · 10 comments · Fixed by #305
Labels

Comments

@jadir-junior
Copy link

jadir-junior commented Jun 30, 2022

Hi,

How can I use @Ouput communincation between my child and parent component?

header-back-button.component.ts (parente component)

@Component({
  selector: 'cebs-header-back-button',
  template: `
    <header>
      <cebs-icon-button
        icon="chevron_left"
        aria-label="back button"
        (clickEvent)="goBack()"
      ></cebs-icon-button>
    </header>
  `,
  styles: [
    `
      :host {
        width: 100%;
      }

      header {
        display: flex;
      }
    `,
  ],
})
export class HeaderBackButtonComponent {
  constructor(private location: Location) {}

  goBack(): void {
    this.location.back()
  }
}

icon-button.component.ts (child component)

@Component({
  selector: 'cebs-icon-button',
  template: `
    <button (click)="onClick()" aria-label="icon button">
      <span class="material-symbols-outlined icon">{{ icon }}</span>
    </button>
  `,
  styles: [
    `
      button {
        border: none;
        width: 40px;
        height: 40px;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: var(--primary-color);
      }

      .icon {
        color: white;
      }
    `,
  ],
})
export class IconButtonComponent {
  @Output() clickEvent = new EventEmitter()

  @Input() icon!: string

  onClick(): void {
    this.clickEvent.emit()
  }
}

header-back-button.component.spec.ts (my test)

describe('HeaderBackButtonComponent', () => {
  it('should render a header back button component', async () => {
    await render(HeaderBackButtonComponent, {
      declarations: [IconButtonComponent],
    })

    expect(screen.getByLabelText(/back button/i)).toBeDefined()
    expect(screen.getByLabelText(/icon button/i)).toBeDefined()
  })

  it('should call a Location.back when user click in the button', async () => {
    const goBackSpy = jest.fn()
    await render(HeaderBackButtonComponent, {
      declarations: [IconButtonComponent],

      componentProperties: {
        goBack: goBackSpy,
      },
    })
    const location = TestBed.inject(Location)
    jest.spyOn(location, 'back')

    const button = screen.getByLabelText(/icon button/i)

    userEvent.click(button)

    expect(goBackSpy).toHaveBeenCalled()
  })
})

when I try to test my expect toHaveBeenCalled is not work, because the output in the child component is not emit

@timdeschryver
Copy link
Member

when I try to test my expect toHaveBeenCalled is not work, because the output in the child component is not emit

This seems to be working on my end.
For an example see https://github.com/testing-library/angular-testing-library/blob/a4eded387122dfb4983812ff5931584bfb550bb6/apps/example-app/src/app/issues/issue-304.spec.ts

@jadir-junior
Copy link
Author

Hi @timdeschryver,
I try to make exactaly equal your example, but I get a error yet.

it('should call a Location.back when user click in the button', async () => {
    await render(HeaderBackButtonComponent, {
      declarations: [IconButtonComponent],
    })

    const location = TestBed.inject(Location)
    jest.spyOn(location, 'back')

    const button = screen.getByLabelText(/icon button/i)
    userEvent.click(button)
    expect(location.back).toHaveBeenCalled()
  })

the error logs

 FAIL  src/app/components/internal/header-back-button/header-back-button.component.spec.ts
  HeaderBackButtonComponent
    ✓ should render a header back button component (78 ms)
    ✕ should call a Location.back when user click in the button (49 ms)

  ● HeaderBackButtonComponent › should call a Location.back when user click in the button

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      27 |     const button = screen.getByLabelText(/icon button/i)
      28 |     userEvent.click(button)
    > 29 |     expect(location.back).toHaveBeenCalled()
         |                           ^
      30 |   })
      31 | })
      32 |

      at src/app/components/internal/header-back-button/header-back-button.component.spec.ts:29:27
      at fulfilled (node_modules/tslib/tslib.js:115:62)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:409:30)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3830:43)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56)
      at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:169:47)
      at node_modules/zone.js/bundles/zone-testing-bundle.umd.js:1326:38
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:443:35)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3861:43)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:442:64)
      at Zone.Object.<anonymous>.Zone.runTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:214:51)
      at drainMicroTaskQueue (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:632:39)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 passed, 2 total
Snapshots:   0 total
Time:        4.252 s, estimated 5 s
Ran all test suites matching /header-back-button/i.

Watch Usage: Press w to show more.

@timdeschryver
Copy link
Member

@jadir-junior
Copy link
Author

Yes, I tried and the same thing happened.

Look

 FAIL  src/app/test/issue-304.spec.ts
  ✕ should call a goBack when user click in the button (119 ms)
  ✕ should call a Location.back when user click in the button (24 ms)

  ● should call a goBack when user click in the button

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      18 |   const button = screen.getByLabelText(/icon button/i)
      19 |   userEvent.click(button)
    > 20 |   expect(goBackSpy).toHaveBeenCalled()
         |                     ^
      21 | })
      22 |
      23 | // don't spy on goBack, this way the implementation of goBack is invoked, and you can test if location.back() is called

      at src/app/test/issue-304.spec.ts:20:21
      at fulfilled (node_modules/tslib/tslib.js:115:62)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:409:30)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3830:43)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56)
      at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:169:47)
      at node_modules/zone.js/bundles/zone-testing-bundle.umd.js:1326:38
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:443:35)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3861:43)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:442:64)
      at Zone.Object.<anonymous>.Zone.runTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:214:51)
      at drainMicroTaskQueue (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:632:39)

  ● should call a Location.back when user click in the button

    expect(jest.fn()).toHaveBeenCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      32 |   const button = screen.getByLabelText(/icon button/i)
      33 |   userEvent.click(button)
    > 34 |   expect(location.back).toHaveBeenCalled()
         |                         ^
      35 | })
      36 |
      37 | @Component({

      at src/app/test/issue-304.spec.ts:34:25
      at fulfilled (node_modules/tslib/tslib.js:115:62)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:409:30)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3830:43)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invoke (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:408:56)
      at Zone.Object.<anonymous>.Zone.run (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:169:47)
      at node_modules/zone.js/bundles/zone-testing-bundle.umd.js:1326:38
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:443:35)
      at ProxyZoneSpec.Object.<anonymous>.ProxyZoneSpec.onInvokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:3861:43)
      at _ZoneDelegate.Object.<anonymous>._ZoneDelegate.invokeTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:442:64)
      at Zone.Object.<anonymous>.Zone.runTask (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:214:51)
      at drainMicroTaskQueue (node_modules/zone.js/bundles/zone-testing-bundle.umd.js:632:39)

Test Suites: 1 failed, 1 total
Tests:       2 failed, 2 total
Snapshots:   0 total
Time:        3.1 s, estimated 6 s
Ran all test suites matching /issue-304/i.

Watch Usage: Press w to show more.

@timdeschryver
Copy link
Member

What versions of Testing Library and UserEvent are you using?

@jadir-junior
Copy link
Author

My packjson is:

{
  "name": "cebs-frontend",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "test:watch:coverage": "jest --watch --coverage",
    "server:coverage": "http-server ./coverage/lcov-report/ -p 8080",
    "e2e": "ng e2e",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "cypress:chrome": "cypress run --browser chrome --headed",
    "style": "prettier --check '**/src/**/*.{scss,ts}'",
    "style:fix": "prettier --write '**/src/**/*.{scss,ts}'"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~14.0.4",
    "@angular/common": "~14.0.4",
    "@angular/compiler": "~14.0.4",
    "@angular/core": "~14.0.4",
    "@angular/forms": "~14.0.4",
    "@angular/platform-browser": "~14.0.4",
    "@angular/platform-browser-dynamic": "~14.0.4",
    "@angular/router": "~14.0.4",
    "rxjs": "~7.5.5",
    "tslib": "^2.4.0",
    "zone.js": "~0.11.6"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~14.0.4",
    "@angular/cli": "~14.0.4",
    "@angular/compiler-cli": "~14.0.4",
    "@cypress/schematic": "^2.0.0",
    "@testing-library/angular": "^12.0.2",
    "@testing-library/jest-dom": "^5.16.4",
    "@testing-library/user-event": "^14.2.1",
    "@types/eslint": "^8.4.3",
    "@types/jest": "^28.1.4",
    "@types/node": "^18.0.0",
    "cypress": "latest",
    "jest": "^28.1.2",
    "jest-preset-angular": "^12.1.0",
    "ng-mocks": "^14.0.1",
    "prettier": "^2.7.1",
    "typescript": "~4.7.4"
  },
  "jest": {
    "preset": "jest-preset-angular",
    "setupFilesAfterEnv": [
      "<rootDir>/src/setup.jest.ts"
    ],
    "testPathIgnorePatterns": [
      "<rootDir>/node_modules/",
      "<rootDir>/dist/"
    ],
    "globals": {
      "ts-jest": {
        "tsconfig": "<rootDir>/tsconfig.spec.json",
        "stringifyContentPathRegex": "\\.html$"
      }
    }
  }
}

@timdeschryver
Copy link
Member

testing-library/user-event v14 implies that all events are Promises.
Have you tried awaiting the click event?

await userEvent.click(element)

@jadir-junior
Copy link
Author

jadir-junior commented Jul 1, 2022

Thank you very much @timdeschryver, You save my life 😆

@timdeschryver
Copy link
Member

Glad we were able to resovle this.
Have a great weekend @jadir-junior !

@github-actions
Copy link

github-actions bot commented Jul 6, 2022

🎉 This issue has been resolved in version 12.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants