import { render , screen , waitFor } from '@testing-library/react' ; import userEvent from '@testing-library/user-event' ; import { mocked } from 'ts-jest/utils' ; import API from '../../../api' ; import { ErrorKind } from '../../../types' ; import alertDispatcher from '../../../utils/alertDispatcher' ; import Values from './' ; jest . mock ( '../../../api' ) ; jest . mock ( '../../../utils/alertDispatcher' ) ; const mockHistoryReplace = jest . fn ( ) ; const scrollToMock = jest . fn ( ) ; const itemScrollMock = jest . fn ( ) ; Object . defineProperty ( HTMLElement . prototype , 'scroll' , { configurable : true , value : itemScrollMock } ) ; window . HTMLElement . prototype . scrollTo = scrollToMock ; jest . mock ( 'react-router-dom' , ( ) => ( { ... ( jest . requireActual ( 'react-router-dom' ) as { } ) , useHistory : ( ) => ( { replace : mockHistoryReplace , } ) , } ) ) ; jest . mock ( 'react-syntax-highlighter' , ( ) => ( ) => < div id = "line_59" > port : < /div>); const defaultProps = { packageId : 'id' , version : '0.1.0' , visibleValues : false , normalizedName : 'pkg' , } ; const YAMLSample = `nameOverride: ""
fullnameOverride: ""
imagePullSecrets: []
imageTag: ""
dynamicResourceNamePrefixEnabled: false
pullPolicy: IfNotPresent
restrictedHTTPClient: false

log:
  level: info
  pretty: false

db:
  host: ""
  port: "5432"
  database: hub
  user: postgres
  password: postgres

email:
  fromName: ""
  from: ""
  replyTo: ""
  smtp:
    auth: plain
    host: ""
    port: 587
    username: ""
    password: ""

creds:
  dockerUsername: ""
  dockerPassword: ""
  githubToken: ""

images:
  store: pg

events:
  scanningErrors: false
  trackingErrors: false

dbMigrator:
  job:
    image:
      repository: artifacthub/db-migrator
  loadSampleData: true
  configDir: "/home/db-migrator/.cfg"

hub:
  ingress:
    enabled: true
    annotations:
      kubernetes.io/ingress.class: nginx
    rules: []
    tls: []
  service:
    type: NodePort
    port: 80
  deploy:
    readinessGates: []
    replicaCount: 1
    image:
      repository: artifacthub/hub
    resources: {}
  server:
    allowPrivateRepositories: false
    cacheDir: ""
    configDir: "/home/hub/.cfg"
    baseURL: ""
    shutdownTimeout: 10s
    motd: ""
    motdSeverity: info
    basicAuth:
      enabled: false
      username: hub
      password: changeme
    cookie:
      hashKey: default-unsafe-key
      secure: false
    csrf:
      authKey: default-unsafe-key
      secure: false
    oauth:
      github:
        enabled: false
        clientID: ""
        clientSecret: ""
        redirectURL: ""
        scopes:
          - read:user
          - user:email
      google:
        enabled: false
        clientID: ""
        clientSecret: ""
        redirectURL: ""
        scopes:
          - https://www.googleapis.com/auth/userinfo.email
          - https://www.googleapis.com/auth/userinfo.profile
      oidc:
        enabled: false
        issuerURL: ""
        clientID: ""
        clientSecret: ""
        redirectURL: ""
        scopes:
          - openid
          - profile
          - email
        skipEmailVerifiedCheck: false
    xffIndex: 0
  analytics:
    gaTrackingID: ""
  theme:
    colors:
      primary: "#417598"
      secondary: "#2D4857"
    images:
      appleTouchIcon192: "/static/media/logo192_v2.png"
      appleTouchIcon512: "/static/media/logo512_v2.png"
      openGraphImage: "/static/media/artifactHub_v2.png"
      shortcutIcon: "/static/media/logo_v2.png"
      websiteLogo: "/static/media/logo/artifacthub-brand-white.svg"
    sampleQueries: []
    siteName: "Artifact hub"

scanner:
  cronjob:
    image:
      repository: artifacthub/scanner
    resources: {}
  concurrency: 10
  trivyURL: ""
  cacheDir: ""
  configDir: "/home/scanner/.cfg"

tracker:
  cronjob:
    image:
      repository: artifacthub/tracker
    resources: {}
  cacheDir: ""
  configDir: "/home/tracker/.cfg"
  concurrency: 10
  repositoriesNames: []
  repositoriesKinds: []
  bypassDigestCheck: false

trivy:
  deploy:
    image: aquasec/trivy:0.20.2
    resources: {}
  persistence:
    enabled: false
    size: 10Gi

# Values for postgresql chart dependency
postgresql:
  enabled: true
  image:
    repository: postgres
    tag: 12
  persistence:
    mountPath: /data
  postgresqlUsername: postgres
  postgresqlPassword: postgres
  postgresqlDatabase: hub
  postgresqlDataDir: /data/pgdata
` ; describe ( 'Values' , ( ) => { afterEach ( ( ) => { jest . resetAllMocks ( ) ; } ) ; it ( 'creates snapshot' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; const { asFragment } = render ( < Values { ... defaultProps } visibleValues / > ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; expect ( asFragment ( ) ) . toMatchSnapshot ( ) ; } ) ; } ) ; describe ( 'Render' , ( ) => { it ( 'renders component' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; expect ( btn ) . toBeInTheDocument ( ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; expect ( API . getChartValues ) . toHaveBeenCalledWith ( defaultProps . packageId , defaultProps . version ) ; } ) ; } ) ; it ( 'opens modal' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; expect ( mockHistoryReplace ) . toHaveBeenCalledTimes ( 1 ) ; expect ( mockHistoryReplace ) . toHaveBeenCalledWith ( { search : '?modal=values' , state : { fromStarredPage : undefined , searchUrlReferer : undefined , } , } ) ; } ) ; expect ( screen . getByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; expect ( screen . getAllByText ( 'Default values' ) ) . toHaveLength ( 2 ) ; } ) ; it ( 'closes modal' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; render ( < Values { ... defaultProps } visibleValues / > ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; const close = screen . getByRole ( 'button' , { name : 'Close modal' } ) ; userEvent . click ( close ) ; expect ( mockHistoryReplace ) . toHaveBeenCalledTimes ( 2 ) ; expect ( mockHistoryReplace ) . toHaveBeenLastCalledWith ( { search : '' , state : { fromStarredPage : undefined , searchUrlReferer : undefined , } , } ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; } ) ; it ( 'calls again to getChartValues when version is different' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; const { rerender } = render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; expect ( API . getChartValues ) . toHaveBeenCalledWith ( defaultProps . packageId , defaultProps . version ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; const close = screen . getByText ( 'Close' ) ; userEvent . click ( close ) ; rerender ( < Values { ... defaultProps } version = "1.0.0" / > ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 2 ) ; expect ( API . getChartValues ) . toHaveBeenCalledWith ( defaultProps . packageId , '1.0.0' ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; } ) ; it ( 'calls again to getChartValues when packageId is different' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; const { rerender } = render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; expect ( API . getChartValues ) . toHaveBeenCalledWith ( defaultProps . packageId , defaultProps . version ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; const close = screen . getByText ( 'Close' ) ; userEvent . click ( close ) ; rerender ( < Values { ... defaultProps } packageId = "id2" / > ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 2 ) ; expect ( API . getChartValues ) . toHaveBeenCalledWith ( 'id2' , defaultProps . version ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; } ) ; it ( 'closes modal when a new pkg is open' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; const { rerender } = render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; userEvent . click ( btn ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; rerender ( < Values { ... defaultProps } packageId = "id2" / > ) ; expect ( screen . queryByRole ( 'dialog' ) ) . toBeNull ( ) ; } ) ; describe ( 'search' , ( ) => { it ( 'renders search bar' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; render ( < Values { ... defaultProps } visibleValues / > ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; userEvent . type ( screen . getByRole ( 'textbox' ) , 'name' ) ; const opts = screen . getAllByTestId ( 'typeaheadDropdownBtn' ) ; expect ( opts ) . toHaveLength ( 10 ) ; expect ( opts [ 0 ] ) . toHaveTextContent ( 'nameOverride' ) ; expect ( opts [ 1 ] ) . toHaveTextContent ( 'fullnameOverride' ) ; expect ( opts [ 2 ] ) . toHaveTextContent ( 'dynamicResourceNamePrefixEnabled' ) ; expect ( opts [ 3 ] ) . toHaveTextContent ( 'email.fromName' ) ; expect ( opts [ 4 ] ) . toHaveTextContent ( 'email.smtp.username' ) ; expect ( opts [ 5 ] ) . toHaveTextContent ( 'creds.dockerUsername' ) ; expect ( opts [ 6 ] ) . toHaveTextContent ( 'hub.server.basicAuth.username' ) ; expect ( opts [ 7 ] ) . toHaveTextContent ( 'hub.theme.siteName' ) ; expect ( opts [ 8 ] ) . toHaveTextContent ( 'tracker.repositoriesNames' ) ; expect ( opts [ 9 ] ) . toHaveTextContent ( 'postgresql.postgresqlUsername' ) ; } ) ; it ( 'clicks option after searching' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; render ( < Values { ... defaultProps } visibleValues / > ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; userEvent . type ( screen . getByRole ( 'textbox' ) , 'name' ) ; const opts = screen . getAllByTestId ( 'typeaheadDropdownBtn' ) ; userEvent . click ( opts [ 8 ] ) ; await waitFor ( ( ) => { expect ( mockHistoryReplace ) . toHaveBeenCalledTimes ( 2 ) ; expect ( mockHistoryReplace ) . toHaveBeenLastCalledWith ( { search : '?modal=values&path=tracker.repositoriesNames' , state : { fromStarredPage : undefined , searchUrlReferer : undefined , } , } ) ; } ) ; } ) ; it ( 'goes to correct position when querystring path is defined' , async ( ) => { mocked ( API ) . getChartValues . mockResolvedValue ( YAMLSample ) ; render ( < Values { ... defaultProps } visibleValues visibleValuesPath = "hub.service.port" / > ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; expect ( await screen . findByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ; await waitFor ( ( ) => { expect ( scrollToMock ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; } ) ; } ) ; describe ( 'when fails' , ( ) => { it ( 'on NotFound' , async ( ) => { mocked ( API ) . getChartValues . mockRejectedValue ( { kind : ErrorKind . NotFound , } ) ; render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; await waitFor ( ( ) => { expect ( alertDispatcher . postAlert ) . toHaveBeenCalledTimes ( 1 ) ; expect ( alertDispatcher . postAlert ) . toHaveBeenCalledWith ( { type : 'danger' , message : 'We could not find the default values for this chart version. Please check that the chart tgz package still exists in the source repository as it might not be available anymore.' , dismissOn : 10000 , } ) ; } ) ; } ) ; it ( 'default error' , async ( ) => { mocked ( API ) . getChartValues . mockRejectedValue ( { kind : ErrorKind . Other } ) ; render ( < Values { ... defaultProps } / > ) ; const btn = screen . getByRole ( 'button' , { name : /Open default values modal/ } ) ; userEvent . click ( btn ) ; await waitFor ( ( ) => { expect ( API . getChartValues ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; await waitFor ( ( ) => { expect ( alertDispatcher . postAlert ) . toHaveBeenCalledTimes ( 1 ) ; expect ( alertDispatcher . postAlert ) . toHaveBeenCalledWith ( { type : 'danger' , message : 'An error occurred getting chart default values, please try again later.' , } ) ; } ) ; } ) ; } ) ; } ) ; } ) ;