All files / generators/_collections test-case-filter.util.ts

97.96% Statements 193/197
92.42% Branches 61/66
100% Functions 3/3
97.96% Lines 193/197

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 1981x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 47x 47x 47x 47x 47x 47x 47x 47x 47x 47x 47x 47x 47x 47x 1x 1x 46x 46x 46x 47x 24x 24x 24x 24x 47x 22x 22x 22x 22x 22x 22x 22x 22x 22x 46x 46x 46x 46x 46x 47x 40x 40x 40x 40x 40x 47x 36x 36x 36x 36x 36x 46x 46x 47x 10x 174x 10x 10x 10x 164x 10x 10x 47x 6x 6x 64x 64x 5x 5x 5x 59x 59x 59x 59x 59x 59x 64x 64x 64x 64x 6x 6x 6x 6x 6x 6x 53x 6x 6x 46x 46x 47x 2x 22x     22x 2x 2x 20x 2x 2x 47x 1x 11x     11x 1x 1x 10x 1x 1x 46x 46x 47x 4x 2x 2x 2x 1x 1x 1x 4x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 46x 46x 46x 1x 1x 756x 756x 756x 756x 63x 63x 756x 672x 672x 21x 21x 21x 1x  
import { DyE2E_FieldTestCase_Type } from '../../contracts/_enums/field-test-case-type.enum';
import { DyE2E_TestExpectation_Type } from '../../contracts/_enums/test-expectation-type.enum';
import { DyE2E_TestRunMode_Type } from '../../contracts/_enums/test-run-mode-type.enum';
import { DyE2E_FieldTestCase_DataModel } from '../../contracts/_models/data-models/field-test-case.data-model';
import { DyE2E_FieldTestSuite_Override } from '../../contracts/_models/interfaces/form-test-suite-settings.interface';
import { DyE2E_FieldSettings_Shape } from '../_models/form-settings-shape.interface';
 
/**
 * Eldönti melyik test-case-ek emit-elődnek a kibocsátott spec-be — a `runMode`
 * + `Settings.validators[]` + per-field override-ok együttese alapján.
 *
 * Ez ahol a generator INTELLIGENS — a field-type-specifikus test-case-set-et
 * a Settings konkrét értékeihez SHAPE-ELI (pl. `oversize` test-case
 * `maxLength`-re igazítja `Settings.maxLength`-ből).
 */
export class DyE2E_TestCaseFilter_Util {
 
  /** A `runMode === smoke`-on belüli auto-keep-szignatúrák. */
  private static readonly SMOKE_KEEP_TYPES: ReadonlySet<DyE2E_FieldTestCase_Type> = new Set([
    DyE2E_FieldTestCase_Type.emptyInput,
    DyE2E_FieldTestCase_Type.ascii,
    DyE2E_FieldTestCase_Type.zero,
    DyE2E_FieldTestCase_Type.one,
    DyE2E_FieldTestCase_Type.todayIso,
    DyE2E_FieldTestCase_Type.firstOption,
    DyE2E_FieldTestCase_Type.toggleOnce,
    DyE2E_FieldTestCase_Type.exactMin,
  ]);
 
  /** A `runMode === nightly` extra-keep-szignatúrái. */
  private static readonly NIGHTLY_EXTRA_TYPES: ReadonlySet<DyE2E_FieldTestCase_Type> = new Set([
    DyE2E_FieldTestCase_Type.rapidToggle,
    DyE2E_FieldTestCase_Type.triplePaste,
    DyE2E_FieldTestCase_Type.doubleClick,
    DyE2E_FieldTestCase_Type.dstSpringForward,
    DyE2E_FieldTestCase_Type.dstFallBack,
  ]);
 
  /**
   * Megszűri + adaptálja a curated test-case-eket a Settings + runMode + override
   * kombinációhoz.
   */
  static filter<T>(
    cases: DyE2E_FieldTestCase_DataModel<T>[],
    fieldSettings: DyE2E_FieldSettings_Shape,
    runMode: DyE2E_TestRunMode_Type,
    override?: DyE2E_FieldTestSuite_Override,
  ): DyE2E_FieldTestCase_DataModel<T>[] {
    let result: DyE2E_FieldTestCase_DataModel<T>[] = cases.filter(
      (c: DyE2E_FieldTestCase_DataModel<T>): boolean => DyE2E_TestCaseFilter_Util.keepByRunMode(c, runMode),
    );
 
    // Disabled-awareness: egy disabled mezővel NEM lehet interaktálni (fill/check/toggle
    // actionability-timeout-ot ad), ezért minden value-interakció esetet eldobunk. A
    // mező izolált tesztben disabled (pl. FDPNX login stayLoggedIn, ami csak a rememberMe
    // bepipálása UTÁN enable-ölődik — a generator izoláltan, rememberMe nélkül navigál).
    if (fieldSettings.disabled === true) {
      return [];
    }
 
    // Required-validator awareness: ha a Settings NEM required, eldobjuk a
    // required-shape eseteket (where expectation === invalid + expectedErrorKey === 'required').
    if (!fieldSettings.required) {
      result = result.filter(
        (c: DyE2E_FieldTestCase_DataModel<T>): boolean =>
          c.expectedErrorKey !== 'required' || c.expectation !== DyE2E_TestExpectation_Type.invalid,
      );
    } else {
      // Ha a mező REQUIRED, az "empty → valid" eset HAMIS: a required-validátor
      // hibát mutat üres inputra (empirikus: FDPNX login usernameEmail/password +blur
      // → required-error). Eldobjuk az empty-valid eseteket (a required-on-empty
      // viselkedést a form-level "submit empty → required fire" teszt fedi).
      result = result.filter(
        (c: DyE2E_FieldTestCase_DataModel<T>): boolean =>
          c.type !== DyE2E_FieldTestCase_Type.emptyInput || c.expectation !== DyE2E_TestExpectation_Type.valid,
      );
    }
 
    // MinLength / maxLength AWARENESS: ha a Settings NEM deklarál min/maxLength-et,
    // eldobjuk a hozzá tartozó invalid-shape eseteket — különben a generált teszt
    // olyan hossz-validátort vár, ami a valós formon nincs (empirikus: FDPNX login
    // password, ahol NINCS min/maxLength, mégis emittálódott a pw:short/pw:oversize).
    if (typeof fieldSettings.minLength !== 'number') {
      result = result.filter(
        (c: DyE2E_FieldTestCase_DataModel<T>): boolean =>
          c.expectedErrorKey !== 'minLength' || c.expectation !== DyE2E_TestExpectation_Type.invalid,
      );
    }
    if (typeof fieldSettings.maxLength !== 'number') {
      result = result.filter(
        (c: DyE2E_FieldTestCase_DataModel<T>): boolean =>
          c.expectedErrorKey !== 'maxLength' || c.expectation !== DyE2E_TestExpectation_Type.invalid,
      );
    }
 
    // MinLength / maxLength shaping.
    if (typeof fieldSettings.maxLength === 'number') {
      result = result.map((c: DyE2E_FieldTestCase_DataModel<T>): DyE2E_FieldTestCase_DataModel<T> => {
        if (c.type === DyE2E_FieldTestCase_Type.oversize && typeof c.inputValue === 'string') {
          const oversizedString: string = 'a'.repeat((fieldSettings.maxLength as number) + 1);
          return new DyE2E_FieldTestCase_DataModel<T>({ ...c, inputValue: oversizedString as unknown as T });
        }
        return c;
      });
    }
    if (typeof fieldSettings.minLength === 'number') {
      const minLen: number = fieldSettings.minLength as number;
      result = result.map((c: DyE2E_FieldTestCase_DataModel<T>): DyE2E_FieldTestCase_DataModel<T> => {
        // Az `undersize` esetet a minLength-1 hosszra alakítjuk (boundary-teszt).
        if (c.type === DyE2E_FieldTestCase_Type.undersize && typeof c.inputValue === 'string') {
          const undersizedString: string = 'a'.repeat(Math.max(0, minLen - 1));
          return new DyE2E_FieldTestCase_DataModel<T>({ ...c, inputValue: undersizedString as unknown as T });
        }
        // Bármely FIX, nem-üres string-input, ami RÖVIDEBB a minLength-nél, INVALID a minLength
        // validátor miatt — még ha a curated default `valid` is (pl. `single-whitespace` egy
        // minLength:6 mezőn). Az üres inputot a `required` kezeli; a már-invalid eseteket nem bántjuk.
        if (
          typeof c.inputValue === 'string'
          && c.inputValue.length > 0
          && c.inputValue.length < minLen
          && c.expectation === DyE2E_TestExpectation_Type.valid
          && c.type !== DyE2E_FieldTestCase_Type.emptyInput
        ) {
          return new DyE2E_FieldTestCase_DataModel<T>({
            ...c,
            expectation: DyE2E_TestExpectation_Type.invalid,
            expectedErrorKey: 'minLength',
          });
        }
        return c;
      });
    }
 
    // Min / max (numerikus) shaping a slider / number-re.
    if (typeof fieldSettings.min === 'number') {
      result = result.map((c: DyE2E_FieldTestCase_DataModel<T>): DyE2E_FieldTestCase_DataModel<T> => {
        if (c.type === DyE2E_FieldTestCase_Type.exactMin) {
          return new DyE2E_FieldTestCase_DataModel<T>({ ...c, inputValue: fieldSettings.min as unknown as T });
        }
        if (c.type === DyE2E_FieldTestCase_Type.belowMin) {
          return new DyE2E_FieldTestCase_DataModel<T>({ ...c, inputValue: String((fieldSettings.min as number) - 1) as unknown as T });
        }
        return c;
      });
    }
    if (typeof fieldSettings.max === 'number') {
      result = result.map((c: DyE2E_FieldTestCase_DataModel<T>): DyE2E_FieldTestCase_DataModel<T> => {
        if (c.type === DyE2E_FieldTestCase_Type.exactMax) {
          return new DyE2E_FieldTestCase_DataModel<T>({ ...c, inputValue: fieldSettings.max as unknown as T });
        }
        if (c.type === DyE2E_FieldTestCase_Type.aboveMax) {
          return new DyE2E_FieldTestCase_DataModel<T>({ ...c, inputValue: String((fieldSettings.max as number) + 1) as unknown as T });
        }
        return c;
      });
    }
 
    // Override-feldolgozás.
    if (override) {
      if (override.onlyCases && override.onlyCases.length > 0) {
        const whitelist: Set<DyE2E_FieldTestCase_Type> = new Set(override.onlyCases);
        result = result.filter((c: DyE2E_FieldTestCase_DataModel<T>): boolean => whitelist.has(c.type));
      } else if (override.skipCases && override.skipCases.length > 0) {
        const blacklist: Set<DyE2E_FieldTestCase_Type> = new Set(override.skipCases);
        result = result.filter((c: DyE2E_FieldTestCase_DataModel<T>): boolean => !blacklist.has(c.type));
      }
      if (override.customCases && override.customCases.length > 0) {
        for (const custom of override.customCases) {
          result.push(new DyE2E_FieldTestCase_DataModel<T>({
            id: `custom:${custom.type}`,
            type: custom.type,
            description: custom.description ?? `custom ${custom.type}`,
            inputValue: (custom.inputValue ?? null) as T | string | null,
            expectation: DyE2E_TestExpectation_Type.valid,
            notes: custom.customSnippet,
          }));
        }
      }
    }
 
    return result;
  }
 
  private static keepByRunMode<T>(
    testCase: DyE2E_FieldTestCase_DataModel<T>,
    runMode: DyE2E_TestRunMode_Type,
  ): boolean {
    if (runMode === DyE2E_TestRunMode_Type.smoke) {
      return DyE2E_TestCaseFilter_Util.SMOKE_KEEP_TYPES.has(testCase.type);
    }
    if (runMode === DyE2E_TestRunMode_Type.full) {
      return !DyE2E_TestCaseFilter_Util.NIGHTLY_EXTRA_TYPES.has(testCase.type);
    }
    // nightly
    return true;
  }
}