shufflecom-calculations 3.0.4 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/games/baccarat.d.ts +54 -0
- package/lib/games/baccarat.js +224 -0
- package/lib/games/baccarat.js.map +1 -0
- package/lib/games/gameCalculation.d.ts +0 -6
- package/lib/games/gameCalculation.js +0 -9
- package/lib/games/gameCalculation.js.map +1 -1
- package/lib/index.d.ts +5 -0
- package/lib/index.js +19 -1
- package/lib/index.js.map +1 -1
- package/lib/regex/index.js +1 -1
- package/lib/regex/index.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/games/baccarat.spec.ts +805 -0
- package/src/games/baccarat.ts +273 -0
- package/src/games/chicken.spec.ts +5 -6
- package/src/games/gameCalculation.ts +0 -25
- package/src/index.ts +5 -0
- package/src/regex/index.ts +2 -2
- package/src/regex/regex.spec.ts +15 -6
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import BigNumber from 'bignumber.js';
|
|
2
|
+
import { CardGames } from './cardGames';
|
|
3
|
+
|
|
4
|
+
export enum BaccaratBetType {
|
|
5
|
+
PLAYER = 'PLAYER',
|
|
6
|
+
BANKER = 'BANKER',
|
|
7
|
+
TIE = 'TIE',
|
|
8
|
+
PLAYER_PAIR = 'PLAYER_PAIR',
|
|
9
|
+
BANKER_PAIR = 'BANKER_PAIR',
|
|
10
|
+
PERFECT_PAIR = 'PERFECT_PAIR',
|
|
11
|
+
EITHER_PAIR = 'EITHER_PAIR',
|
|
12
|
+
PLAYER_BONUS = 'PLAYER_BONUS',
|
|
13
|
+
BANKER_BONUS = 'BANKER_BONUS',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum BaccaratOutcome {
|
|
17
|
+
PLAYER_WIN = 'PLAYER_WIN',
|
|
18
|
+
BANKER_WIN = 'BANKER_WIN',
|
|
19
|
+
TIE = 'TIE',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface BaccaratBet {
|
|
23
|
+
type: BaccaratBetType;
|
|
24
|
+
amount: BigNumber;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface BaccaratGameResult {
|
|
28
|
+
playerCards: number[]; // card indices 0–51, 2 or 3 cards
|
|
29
|
+
bankerCards: number[]; // card indices 0–51, 2 or 3 cards
|
|
30
|
+
playerHandValue: number; // 0–9
|
|
31
|
+
bankerHandValue: number; // 0–9
|
|
32
|
+
outcome: BaccaratOutcome;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface BaccaratTrendData {
|
|
36
|
+
outcome: BaccaratOutcome;
|
|
37
|
+
playerPair: boolean;
|
|
38
|
+
bankerPair: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const PLAYER_WIN_MULTIPLIER = new BigNumber(2); // 1:1
|
|
42
|
+
const BANKER_WIN_MULTIPLIER = new BigNumber(1.95); // 0.95:1
|
|
43
|
+
const TIE_MULTIPLIER = new BigNumber(9); // 8:1
|
|
44
|
+
const PAIR_MULTIPLIER = new BigNumber(12); // 11:1
|
|
45
|
+
const EITHER_PAIR_MULTIPLIER = new BigNumber(6); // 5:1
|
|
46
|
+
const PERFECT_PAIR_ONE_HAND_MULTIPLIER = new BigNumber(26); // 25:1
|
|
47
|
+
const PERFECT_PAIR_BOTH_HANDS_MULTIPLIER = new BigNumber(201); // 200:1
|
|
48
|
+
const BONUS_NATURAL_WIN_MULTIPLIER = new BigNumber(2); // 1:1
|
|
49
|
+
const BONUS_NATURAL_TIE_MULTIPLIER = new BigNumber(1); // push
|
|
50
|
+
|
|
51
|
+
const BONUS_NON_NATURAL_PAYOUT: Record<number, BigNumber> = {
|
|
52
|
+
4: new BigNumber(2), // 1:1
|
|
53
|
+
5: new BigNumber(3), // 2:1
|
|
54
|
+
6: new BigNumber(5), // 4:1
|
|
55
|
+
7: new BigNumber(7), // 6:1
|
|
56
|
+
8: new BigNumber(11), // 10:1
|
|
57
|
+
9: new BigNumber(31), // 30:1
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export class Baccarat {
|
|
61
|
+
static getBaccaratCardValue(cardIndex: number): number {
|
|
62
|
+
const { value } = CardGames.getCardDetails(cardIndex);
|
|
63
|
+
if (value === '10' || value === 'J' || value === 'Q' || value === 'K') {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
if (value === 'A') {
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
return parseInt(value, 10);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static calcHandValue(cards: number[]): number {
|
|
73
|
+
return cards.reduce((sum, card) => (sum + this.getBaccaratCardValue(card)) % 10, 0);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static isNatural(handValue: number, cards: number[]): boolean {
|
|
77
|
+
return (handValue === 8 || handValue === 9) && cards.length === 2;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
private static shouldPlayerDrawThird(playerValue: number): boolean {
|
|
81
|
+
return playerValue <= 5;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private static shouldBankerDrawThird(bankerValue: number, playerThirdCardValue: number | null): boolean {
|
|
85
|
+
if (playerThirdCardValue === null) {
|
|
86
|
+
return bankerValue <= 5;
|
|
87
|
+
}
|
|
88
|
+
if (bankerValue <= 2) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (bankerValue === 3) {
|
|
92
|
+
return playerThirdCardValue !== 8;
|
|
93
|
+
}
|
|
94
|
+
if (bankerValue === 4) {
|
|
95
|
+
return [2, 3, 4, 5, 6, 7].includes(playerThirdCardValue);
|
|
96
|
+
}
|
|
97
|
+
if (bankerValue === 5) {
|
|
98
|
+
return [4, 5, 6, 7].includes(playerThirdCardValue);
|
|
99
|
+
}
|
|
100
|
+
if (bankerValue === 6) {
|
|
101
|
+
return [6, 7].includes(playerThirdCardValue);
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static getGameResult(hexString: string): BaccaratGameResult {
|
|
107
|
+
const cardIndices = CardGames.getResults([hexString]).slice(0, 6);
|
|
108
|
+
|
|
109
|
+
if (cardIndices.length !== 6) {
|
|
110
|
+
throw new Error(`Expected 6 card indices for Baccarat, but got ${cardIndices.length}.`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const playerCards: number[] = [cardIndices[0], cardIndices[2]];
|
|
114
|
+
const bankerCards: number[] = [cardIndices[1], cardIndices[3]];
|
|
115
|
+
|
|
116
|
+
let playerHandValue = this.calcHandValue(playerCards);
|
|
117
|
+
let bankerHandValue = this.calcHandValue(bankerCards);
|
|
118
|
+
|
|
119
|
+
let thirdCardIndex = 4; // Index for player's third card if drawn, or banker's third card if player doesn't draw
|
|
120
|
+
const isNaturalWin = this.isNatural(playerHandValue, playerCards) || this.isNatural(bankerHandValue, bankerCards);
|
|
121
|
+
if (!isNaturalWin) {
|
|
122
|
+
let playerThirdCardValue: number | null = null;
|
|
123
|
+
|
|
124
|
+
if (this.shouldPlayerDrawThird(playerHandValue)) {
|
|
125
|
+
playerCards.push(cardIndices[thirdCardIndex]);
|
|
126
|
+
playerThirdCardValue = this.getBaccaratCardValue(cardIndices[thirdCardIndex]);
|
|
127
|
+
playerHandValue = this.calcHandValue(playerCards);
|
|
128
|
+
thirdCardIndex++;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (this.shouldBankerDrawThird(bankerHandValue, playerThirdCardValue)) {
|
|
132
|
+
bankerCards.push(cardIndices[thirdCardIndex]);
|
|
133
|
+
bankerHandValue = this.calcHandValue(bankerCards);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
let outcome: BaccaratOutcome;
|
|
138
|
+
|
|
139
|
+
if (playerHandValue === bankerHandValue) {
|
|
140
|
+
outcome = BaccaratOutcome.TIE;
|
|
141
|
+
} else {
|
|
142
|
+
outcome = playerHandValue > bankerHandValue ? BaccaratOutcome.PLAYER_WIN : BaccaratOutcome.BANKER_WIN;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { playerCards, bankerCards, playerHandValue, bankerHandValue, outcome };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
static hasPair(cards: number[]): boolean {
|
|
149
|
+
return CardGames.getCardDetails(cards[0]).value === CardGames.getCardDetails(cards[1]).value;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static getTrendData(result: BaccaratGameResult): BaccaratTrendData {
|
|
153
|
+
return {
|
|
154
|
+
outcome: result.outcome,
|
|
155
|
+
playerPair: Baccarat.hasPair(result.playerCards),
|
|
156
|
+
bankerPair: Baccarat.hasPair(result.bankerCards),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static hasPerfectPair(cards: number[]): boolean {
|
|
161
|
+
return cards[0] === cards[1];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private static getBonusPayout(betType: BaccaratBetType.PLAYER_BONUS | BaccaratBetType.BANKER_BONUS, result: BaccaratGameResult): BigNumber {
|
|
165
|
+
const { playerCards, bankerCards, playerHandValue, bankerHandValue, outcome } = result;
|
|
166
|
+
const isPlayerBonus = betType === BaccaratBetType.PLAYER_BONUS;
|
|
167
|
+
|
|
168
|
+
const isNaturalTie =
|
|
169
|
+
this.isNatural(playerHandValue, playerCards) && this.isNatural(bankerHandValue, bankerCards) && outcome === BaccaratOutcome.TIE;
|
|
170
|
+
if (isNaturalTie) {
|
|
171
|
+
return BONUS_NATURAL_TIE_MULTIPLIER;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sideBetWins = isPlayerBonus ? outcome === BaccaratOutcome.PLAYER_WIN : outcome === BaccaratOutcome.BANKER_WIN;
|
|
175
|
+
|
|
176
|
+
if (!sideBetWins) {
|
|
177
|
+
return new BigNumber(0);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const sideHandValue = isPlayerBonus ? playerHandValue : bankerHandValue;
|
|
181
|
+
const otherHandValue = isPlayerBonus ? bankerHandValue : playerHandValue;
|
|
182
|
+
|
|
183
|
+
if (this.isNatural(sideHandValue, isPlayerBonus ? playerCards : bankerCards)) {
|
|
184
|
+
return BONUS_NATURAL_WIN_MULTIPLIER;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const margin = sideHandValue - otherHandValue;
|
|
188
|
+
return BONUS_NON_NATURAL_PAYOUT[margin] ?? new BigNumber(0);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
static calcBetPayouts(bets: BaccaratBet[], result: BaccaratGameResult): { payout: BigNumber; multiplier: BigNumber } {
|
|
192
|
+
const { outcome } = result;
|
|
193
|
+
|
|
194
|
+
const playerHasPair = this.hasPair(result.playerCards);
|
|
195
|
+
const bankerHasPair = this.hasPair(result.bankerCards);
|
|
196
|
+
const playerHasPerfectPair = this.hasPerfectPair(result.playerCards);
|
|
197
|
+
const bankerHasPerfectPair = this.hasPerfectPair(result.bankerCards);
|
|
198
|
+
|
|
199
|
+
let totalPayout = new BigNumber(0);
|
|
200
|
+
let totalBetAmount = new BigNumber(0);
|
|
201
|
+
|
|
202
|
+
for (const bet of bets) {
|
|
203
|
+
totalBetAmount = totalBetAmount.plus(bet.amount);
|
|
204
|
+
let betPayout = new BigNumber(0);
|
|
205
|
+
|
|
206
|
+
switch (bet.type) {
|
|
207
|
+
case BaccaratBetType.PLAYER:
|
|
208
|
+
if (outcome === BaccaratOutcome.PLAYER_WIN) {
|
|
209
|
+
betPayout = bet.amount.times(PLAYER_WIN_MULTIPLIER);
|
|
210
|
+
} else if (outcome === BaccaratOutcome.TIE) {
|
|
211
|
+
betPayout = bet.amount;
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
|
|
215
|
+
case BaccaratBetType.BANKER:
|
|
216
|
+
if (outcome === BaccaratOutcome.BANKER_WIN) {
|
|
217
|
+
betPayout = bet.amount.times(BANKER_WIN_MULTIPLIER);
|
|
218
|
+
} else if (outcome === BaccaratOutcome.TIE) {
|
|
219
|
+
betPayout = bet.amount;
|
|
220
|
+
}
|
|
221
|
+
break;
|
|
222
|
+
|
|
223
|
+
case BaccaratBetType.TIE:
|
|
224
|
+
if (outcome === BaccaratOutcome.TIE) {
|
|
225
|
+
betPayout = bet.amount.times(TIE_MULTIPLIER);
|
|
226
|
+
}
|
|
227
|
+
break;
|
|
228
|
+
|
|
229
|
+
case BaccaratBetType.PLAYER_PAIR:
|
|
230
|
+
if (playerHasPair) {
|
|
231
|
+
betPayout = bet.amount.times(PAIR_MULTIPLIER);
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
|
|
235
|
+
case BaccaratBetType.BANKER_PAIR:
|
|
236
|
+
if (bankerHasPair) {
|
|
237
|
+
betPayout = bet.amount.times(PAIR_MULTIPLIER);
|
|
238
|
+
}
|
|
239
|
+
break;
|
|
240
|
+
|
|
241
|
+
case BaccaratBetType.PERFECT_PAIR:
|
|
242
|
+
if (playerHasPerfectPair && bankerHasPerfectPair) {
|
|
243
|
+
betPayout = bet.amount.times(PERFECT_PAIR_BOTH_HANDS_MULTIPLIER);
|
|
244
|
+
} else if (playerHasPerfectPair || bankerHasPerfectPair) {
|
|
245
|
+
betPayout = bet.amount.times(PERFECT_PAIR_ONE_HAND_MULTIPLIER);
|
|
246
|
+
}
|
|
247
|
+
break;
|
|
248
|
+
|
|
249
|
+
case BaccaratBetType.EITHER_PAIR:
|
|
250
|
+
if (playerHasPair || bankerHasPair) {
|
|
251
|
+
betPayout = bet.amount.times(EITHER_PAIR_MULTIPLIER);
|
|
252
|
+
}
|
|
253
|
+
break;
|
|
254
|
+
|
|
255
|
+
case BaccaratBetType.PLAYER_BONUS:
|
|
256
|
+
case BaccaratBetType.BANKER_BONUS:
|
|
257
|
+
betPayout = bet.amount.times(this.getBonusPayout(bet.type, result));
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
totalPayout = totalPayout.plus(betPayout);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const multiplier = totalBetAmount.gt(0) ? totalPayout.dividedBy(totalBetAmount) : new BigNumber(0);
|
|
265
|
+
return { payout: totalPayout, multiplier };
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
static getGameOutcome(bets: BaccaratBet[], hexString: string): { result: BaccaratGameResult; payout: BigNumber; multiplier: BigNumber } {
|
|
269
|
+
const result = this.getGameResult(hexString);
|
|
270
|
+
const { payout, multiplier } = this.calcBetPayouts(bets, result);
|
|
271
|
+
return { result, payout, multiplier };
|
|
272
|
+
}
|
|
273
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { createHmac } from 'crypto';
|
|
1
2
|
import { Chicken, ChickenDifficulty } from './chicken';
|
|
2
|
-
import { GameCalculation } from './gameCalculation';
|
|
3
3
|
|
|
4
4
|
const edgeBps = 200;
|
|
5
5
|
|
|
@@ -89,11 +89,10 @@ describe('Chicken', () => {
|
|
|
89
89
|
];
|
|
90
90
|
|
|
91
91
|
gameSeeds.forEach(e => {
|
|
92
|
-
const resultHex =
|
|
93
|
-
|
|
94
|
-
clientSeed
|
|
95
|
-
|
|
96
|
-
rounds: e.rounds,
|
|
92
|
+
const resultHex = Array.from(Array(e.rounds).keys()).map(round => {
|
|
93
|
+
const hmac = createHmac('sha256', e.serverSeed);
|
|
94
|
+
hmac.update(`${e.clientSeed}:${e.nonce}:${round}`);
|
|
95
|
+
return hmac.digest('hex');
|
|
97
96
|
});
|
|
98
97
|
const results = Chicken.getResults(resultHex, e.difficulty);
|
|
99
98
|
expect(results).toEqual(e.results);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import BigNumber from 'bignumber.js';
|
|
2
2
|
import { hexToBytes } from '../utils/hex-to-bytes';
|
|
3
|
-
import { createHmac } from 'crypto';
|
|
4
3
|
|
|
5
4
|
export abstract class GameCalculation {
|
|
6
5
|
private static readonly BYTE_TOTAL = new BigNumber(256);
|
|
@@ -126,28 +125,4 @@ export abstract class GameCalculation {
|
|
|
126
125
|
|
|
127
126
|
return results;
|
|
128
127
|
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Generate provably fair random hex strings using HMAC-SHA256
|
|
132
|
-
*
|
|
133
|
-
* @param serverSeed - Secret server seed (revealed after game/rotation)
|
|
134
|
-
* @param clientSeed - Player-provided seed for transparency
|
|
135
|
-
* @param nonce - Sequential number that increments with each bet
|
|
136
|
-
* @param rounds - How many hex strings to generate (each = 32 bytes of randomness)
|
|
137
|
-
* @returns Array of hex strings, each representing 32 bytes of cryptographic randomness
|
|
138
|
-
*/
|
|
139
|
-
static generateDigestHex({
|
|
140
|
-
serverSeed,
|
|
141
|
-
clientSeed,
|
|
142
|
-
nonce,
|
|
143
|
-
rounds,
|
|
144
|
-
}: { serverSeed: string; clientSeed: string; nonce: string; rounds: number }): string[] {
|
|
145
|
-
const results = Array.from(Array(rounds).keys()).map(round => {
|
|
146
|
-
const hmac = createHmac('sha256', serverSeed);
|
|
147
|
-
hmac.update(`${clientSeed}:${nonce}:${round}`);
|
|
148
|
-
return hmac.digest('hex');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return results;
|
|
152
|
-
}
|
|
153
128
|
}
|
package/src/index.ts
CHANGED
|
@@ -28,5 +28,10 @@ export {
|
|
|
28
28
|
twentyOnePlusThreePayout,
|
|
29
29
|
HandOutcome,
|
|
30
30
|
} from './games/blackjack';
|
|
31
|
+
export { Baccarat, BaccaratBetType, BaccaratOutcome } from './games/baccarat';
|
|
32
|
+
export type { BaccaratBet, BaccaratGameResult } from './games/baccarat';
|
|
33
|
+
export { Chicken, ChickenDifficulty } from './games/chicken';
|
|
34
|
+
export { Tower, TowerDifficulty, TOWER_DIFFICULTY_TO_CONFIG, TOWER_TOTAL_ROWS } from './games/tower';
|
|
35
|
+
export { Wheel, WheelRiskLevel, WheelSegments, WHEEL_MULTIPLIERS, WHEEL_SEGMENTS_TO_NUMBER } from './games/wheel';
|
|
31
36
|
export { formatSelectionName } from './utils/sports-name';
|
|
32
37
|
export { SportsContentWithFixturesInfo } from './utils/sports-content-fixture.types';
|
package/src/regex/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Must
|
|
2
|
-
export const PWD_REGEX =
|
|
1
|
+
// Must contain at least 1 alphabetical character and 1 number. Can include any symbols
|
|
2
|
+
export const PWD_REGEX = /^(?=.*[0-9])(?=.*[a-zA-Z])(?=\S+$).{8,24}$/i;
|
|
3
3
|
// Must contain lowercase alphabetical characters, can include underscores, no other symbols
|
|
4
4
|
export const USERNAME_REGEX = /^[a-z\d]{3,16}$/i;
|
|
5
5
|
|
package/src/regex/regex.spec.ts
CHANGED
|
@@ -11,20 +11,29 @@ import {
|
|
|
11
11
|
|
|
12
12
|
describe('regex', () => {
|
|
13
13
|
describe('PWD_REGEX', () => {
|
|
14
|
+
it('should allow for passwords that includes 1 character and 1 number with 8 or more character', () => {
|
|
15
|
+
expect(PWD_REGEX.test('abcdefgh1')).toBe(true);
|
|
16
|
+
expect(PWD_REGEX.test('abcdefgh1!@#$%^&*()')).toBe(true);
|
|
17
|
+
expect(PWD_REGEX.test('1234567a')).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
|
|
14
20
|
it('should not allow passwords with less than 8 characters', () => {
|
|
15
21
|
expect(PWD_REGEX.test('abcdef1')).toBe(false);
|
|
16
22
|
expect(PWD_REGEX.test('123456a')).toBe(false);
|
|
17
23
|
});
|
|
18
24
|
|
|
19
|
-
it('should not
|
|
20
|
-
expect(PWD_REGEX.test('
|
|
25
|
+
it('should not allow passwords that do not include a letter', () => {
|
|
26
|
+
expect(PWD_REGEX.test('12345678')).toBe(false);
|
|
27
|
+
expect(PWD_REGEX.test('12345678@!@#')).toBe(false);
|
|
21
28
|
});
|
|
22
29
|
|
|
23
|
-
it('should allow passwords
|
|
24
|
-
expect(PWD_REGEX.test('
|
|
25
|
-
expect(PWD_REGEX.test('abcdefgh')).toBe(
|
|
26
|
-
|
|
30
|
+
it('should not allow passwords that do not include a letter', () => {
|
|
31
|
+
expect(PWD_REGEX.test('abcdefgh')).toBe(false);
|
|
32
|
+
expect(PWD_REGEX.test('abcdefgh!@#$')).toBe(false);
|
|
33
|
+
});
|
|
27
34
|
|
|
35
|
+
it('should not exceed 24 characters', () => {
|
|
36
|
+
expect(PWD_REGEX.test('0123456789abcdefghijklmnopqrst')).toBe(false);
|
|
28
37
|
});
|
|
29
38
|
});
|
|
30
39
|
|