github.com/freiheit-com/kuberpult@v1.24.2-0.20240328135542-315d5630abe6/services/frontend-service/src/ui/components/chip/EnvironmentGroupChip.test.tsx (about)

     1  /*This file is part of kuberpult.
     2  
     3  Kuberpult is free software: you can redistribute it and/or modify
     4  it under the terms of the Expat(MIT) License as published by
     5  the Free Software Foundation.
     6  
     7  Kuberpult is distributed in the hope that it will be useful,
     8  but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    10  MIT License for more details.
    11  
    12  You should have received a copy of the MIT License
    13  along with kuberpult. If not, see <https://directory.fsf.org/wiki/License:Expat>.
    14  
    15  Copyright 2023 freiheit.com*/
    16  import { EnvironmentChip, EnvironmentChipProps, EnvironmentGroupChip } from './EnvironmentGroupChip';
    17  import { fireEvent, render } from '@testing-library/react';
    18  import { Environment, EnvironmentGroup, Lock, Priority } from '../../../api/api';
    19  import { EnvironmentGroupExtended, UpdateOverview } from '../../utils/store';
    20  import { Spy } from 'spy4js';
    21  
    22  const mock_addAction = Spy.mockModule('../../utils/store', 'addAction');
    23  
    24  const makeLock = (id: string): Lock => ({
    25      message: id,
    26      lockId: id,
    27  });
    28  
    29  describe('EnvironmentChip', () => {
    30      const env: Environment = {
    31          name: 'Test Me',
    32          distanceToUpstream: 0,
    33          priority: Priority.PROD,
    34          locks: {},
    35          applications: {},
    36      };
    37      const envGroup: EnvironmentGroup = {
    38          distanceToUpstream: 0,
    39          environments: [env],
    40          environmentGroupName: 'Test Me Group',
    41          priority: Priority.PROD,
    42      };
    43      const getNode = (overloads?: Partial<EnvironmentChipProps>) => (
    44          <EnvironmentChip app="app2" className={'chip--test'} env={env} envGroup={envGroup} {...overloads} />
    45      );
    46      const getWrapper = (overloads?: Partial<EnvironmentChipProps>) => render(getNode(overloads));
    47      it('renders a chip', () => {
    48          // given
    49          UpdateOverview.set({
    50              environmentGroups: [
    51                  {
    52                      environments: [env],
    53                      environmentGroupName: 'dontcare',
    54                      distanceToUpstream: 0,
    55                      priority: Priority.UNRECOGNIZED,
    56                  },
    57              ],
    58          });
    59          // then
    60          const { container } = getWrapper();
    61          expect(container.firstChild).toMatchInlineSnapshot(`
    62              <div
    63                class="mdc-evolution-chip chip--test environment-priority-prod"
    64                role="row"
    65              >
    66                <span
    67                  class="mdc-evolution-chip__cell mdc-evolution-chip__cell--primary mdc-evolution-chip__action--primary"
    68                  role="gridcell"
    69                >
    70                  <span
    71                    class="mdc-evolution-chip__text-name"
    72                  >
    73                    <span>
    74                      Test Me
    75                    </span>
    76                  </span>
    77                   
    78                  <span
    79                    class="mdc-evolution-chip__text-numbers"
    80                  />
    81                  <div
    82                    class="chip--test env-locks"
    83                  />
    84                </span>
    85              </div>
    86          `);
    87      });
    88      it('renders a short form tag chip', () => {
    89          const wrapper = getWrapper({
    90              smallEnvChip: true,
    91              env: {
    92                  ...env,
    93                  locks: {
    94                      lock1: makeLock('lock1'),
    95                      lock2: makeLock('lock2'),
    96                  },
    97              },
    98          });
    99          const { container } = wrapper;
   100          expect(container.querySelector('.mdc-evolution-chip__text-name')?.textContent).toBe(env.name[0].toUpperCase());
   101          // only show one lock icon in the small env tag
   102          expect(container.querySelectorAll('.env-card-env-lock-icon').length).toBe(1);
   103      });
   104      it('renders env locks in big env chip', () => {
   105          UpdateOverview.set({
   106              environmentGroups: [
   107                  {
   108                      environments: [
   109                          {
   110                              ...env,
   111                              locks: {
   112                                  'test-lock1': makeLock('test-lock1'),
   113                                  'test-lock2': makeLock('test-lock2'),
   114                              },
   115                          },
   116                      ],
   117                      priority: Priority.UNRECOGNIZED,
   118                      environmentGroupName: 'dontcare',
   119                      distanceToUpstream: 0,
   120                  },
   121              ],
   122          });
   123  
   124          const wrapper = getWrapper({
   125              // big chip shows all locks
   126              smallEnvChip: false,
   127              env: {
   128                  ...env,
   129                  locks: {
   130                      'test-lock1': makeLock('test-lock1'),
   131                      'test-lock2': makeLock('test-lock2'),
   132                  },
   133              },
   134          });
   135  
   136          const { container } = wrapper;
   137          expect(container.querySelectorAll('.env-card-env-lock-icon').length).toBe(2);
   138          const lock1 = container.querySelectorAll('.button-lock')[0];
   139          fireEvent.click(lock1);
   140          mock_addAction.addAction.wasCalled();
   141          expect(mock_addAction.addAction.getCallArguments()[0]).toHaveProperty(
   142              'action.deleteEnvironmentLock.lockId',
   143              'test-lock1'
   144          );
   145      });
   146  });
   147  
   148  const envGroupPairFromPrios = (
   149      envPrio: Priority,
   150      envGroupPrio: Priority
   151  ): { env: Environment; envGroup: EnvironmentGroup } => {
   152      const env: Environment = {
   153          applications: {},
   154          distanceToUpstream: -1, // shouldn't matter, if this value is used an error will be thrown
   155          locks: {},
   156          name: 'Test me',
   157          priority: envPrio,
   158      };
   159      const envGroup: EnvironmentGroup = {
   160          distanceToUpstream: -1, // shouldn't matter, if this value is used an error will be thrown
   161          environmentGroupName: 'Test me group',
   162          environments: [env],
   163          priority: envGroupPrio,
   164      };
   165  
   166      return { env, envGroup };
   167  };
   168  
   169  type TestDataEnvs = {
   170      envGroupPair: {
   171          env: Environment;
   172          envGroup: EnvironmentGroup;
   173      };
   174      expectedClass: string;
   175  };
   176  
   177  const envChipData: Array<TestDataEnvs> = [
   178      {
   179          envGroupPair: envGroupPairFromPrios(Priority.PROD, Priority.PROD),
   180          expectedClass: 'prod',
   181      },
   182      {
   183          envGroupPair: envGroupPairFromPrios(Priority.PRE_PROD, Priority.PRE_PROD),
   184          expectedClass: 'pre_prod',
   185      },
   186      {
   187          envGroupPair: envGroupPairFromPrios(Priority.UPSTREAM, Priority.UPSTREAM),
   188          expectedClass: 'upstream',
   189      },
   190      {
   191          envGroupPair: envGroupPairFromPrios(Priority.OTHER, Priority.OTHER),
   192          expectedClass: 'other',
   193      },
   194      {
   195          // important case: env and group have different priorities, the priority of the group should take precedence
   196          envGroupPair: envGroupPairFromPrios(Priority.UPSTREAM, Priority.PROD),
   197          expectedClass: 'prod',
   198      },
   199      {
   200          // important case: env and group have different priorities, the priority of the group should take precedence
   201          envGroupPair: envGroupPairFromPrios(Priority.PRE_PROD, Priority.CANARY),
   202          expectedClass: 'canary',
   203      },
   204  ];
   205  
   206  describe.each(envChipData)(`EnvironmentChip with envPrio Classname`, (testcase) => {
   207      it(`with envPrio=${testcase.envGroupPair.env.priority} and groupPrio=${testcase.envGroupPair.envGroup.priority}`, () => {
   208          const env = testcase.envGroupPair.env;
   209          const group = testcase.envGroupPair.envGroup;
   210          const getNode = () => <EnvironmentChip app="app1" className={'chip--hello'} env={env} envGroup={group} />;
   211          const getWrapper = () => render(getNode());
   212          const { container } = getWrapper();
   213          expect(container.firstChild).toHaveClass(
   214              'mdc-evolution-chip chip--hello environment-priority-' + testcase.expectedClass
   215          );
   216      });
   217  });
   218  
   219  const envGroupFromPrio = (prio: Priority, numEnvsInGroup: number, envs: Environment[]): EnvironmentGroupExtended => ({
   220      numberOfEnvsInGroup: numEnvsInGroup,
   221      environmentGroupName: 'i am the group',
   222      environments: envs,
   223      distanceToUpstream: 0,
   224      priority: Priority.UNRECOGNIZED,
   225  });
   226  
   227  type TestDataGroups = {
   228      envGroup: EnvironmentGroupExtended;
   229      expectedClass: string;
   230      expectedNumbers: string;
   231      expectedDisplayName: string;
   232  };
   233  
   234  const envFromPrio = (prio: Priority): Environment => ({
   235      name: 'Test Me',
   236      distanceToUpstream: 0,
   237      priority: prio,
   238      locks: {},
   239      applications: {},
   240  });
   241  
   242  const envGroupChipData: Array<TestDataGroups> = [
   243      {
   244          envGroup: envGroupFromPrio(Priority.PROD, 1, [envFromPrio(Priority.PROD)]),
   245          expectedClass: 'prod',
   246          expectedNumbers: '(1)',
   247          expectedDisplayName: 'Test Me',
   248      },
   249      {
   250          envGroup: envGroupFromPrio(Priority.PROD, 3, [envFromPrio(Priority.UPSTREAM), envFromPrio(Priority.PROD)]),
   251          expectedClass: 'upstream',
   252          expectedNumbers: '(2/3)',
   253          expectedDisplayName: 'i am the group',
   254      },
   255  ];
   256  
   257  describe.each(envGroupChipData)(`EnvironmentGroupChip with different envs`, (testcase) => {
   258      it(`with envPrio=${testcase.expectedClass}`, () => {
   259          const getNode = () => (
   260              <EnvironmentGroupChip app="app1" className={'chip--hello'} envGroup={testcase.envGroup} />
   261          );
   262          const getWrapper = () => render(getNode());
   263          const { container } = getWrapper();
   264          expect(container.querySelector('.mdc-evolution-chip__text-name')?.textContent).toContain(
   265              testcase.expectedDisplayName
   266          );
   267          expect(container.querySelector('.mdc-evolution-chip__text-numbers')?.textContent).toContain(
   268              testcase.expectedNumbers
   269          );
   270      });
   271  });