prettier
This commit is contained in:
1 parent
f46969549e
commit
b9c25369c7
15 files changed
+189
-147
No files matched your search
+16
@@ -3,6 +3,7 @@
|
||||
## Quick Start
|
||||
|
||||
Run all tests:
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
@@ -31,25 +32,30 @@ src/app/
|
||||
## What's Tested
|
||||
|
||||
### Components (4)
|
||||
|
||||
- ✅ **App** - Main application component
|
||||
- ✅ **ChampionRandomizerComponent** - Core randomization logic
|
||||
- ✅ **ControlHeaderComponent** - User controls
|
||||
- ✅ **LaneCardComponent** - Individual lane display
|
||||
|
||||
### Services (3)
|
||||
|
||||
- ✅ **ChampionDataService** - Data fetching and caching
|
||||
- ✅ **ImagePreloadService** - Image preloading
|
||||
- ✅ **RandomNumber** - Secure random generation
|
||||
|
||||
### Directives (1)
|
||||
|
||||
- ✅ **PreloadLinkDirective** - Link preloading
|
||||
|
||||
### Interceptors (1)
|
||||
|
||||
- ✅ **imageCacheInterceptor** - HTTP caching
|
||||
|
||||
## Key Test Scenarios
|
||||
|
||||
### Champion Randomizer
|
||||
|
||||
- Random champion assignment for each lane
|
||||
- Lane enable/disable functionality
|
||||
- Reroll system with bank management
|
||||
@@ -58,6 +64,7 @@ src/app/
|
||||
- Copy draft to clipboard
|
||||
|
||||
### Champion Data Service
|
||||
|
||||
- API data fetching
|
||||
- LocalStorage caching (24-hour expiry)
|
||||
- Cache validation and invalidation
|
||||
@@ -65,11 +72,13 @@ src/app/
|
||||
- Champion filtering and sorting
|
||||
|
||||
### Random Number Service
|
||||
|
||||
- Cryptographically secure random numbers
|
||||
- Range validation
|
||||
- Edge case handling
|
||||
|
||||
### Image Management
|
||||
|
||||
- Cache control headers
|
||||
- Image preloading
|
||||
- Duplicate prevention
|
||||
@@ -78,6 +87,7 @@ src/app/
|
||||
## Test Configuration
|
||||
|
||||
The project uses:
|
||||
|
||||
- **Framework**: Jasmine
|
||||
- **Runner**: Karma
|
||||
- **Browser**: Chrome (or ChromeHeadless for CI)
|
||||
@@ -85,6 +95,7 @@ The project uses:
|
||||
## Continuous Integration
|
||||
|
||||
For CI environments without a display:
|
||||
|
||||
```bash
|
||||
npm test -- --watch=false --browsers=ChromeHeadless
|
||||
```
|
||||
@@ -92,6 +103,7 @@ npm test -- --watch=false --browsers=ChromeHeadless
|
||||
## Code Coverage
|
||||
|
||||
Generate coverage report:
|
||||
|
||||
```bash
|
||||
ng test --no-watch --code-coverage
|
||||
```
|
||||
@@ -110,20 +122,24 @@ Coverage report will be available in `coverage/` directory.
|
||||
## Troubleshooting
|
||||
|
||||
### Tests won't run
|
||||
|
||||
- Ensure all dependencies are installed: `npm install`
|
||||
- Check that Chrome is installed for Karma
|
||||
|
||||
### Specific test failing
|
||||
|
||||
- Run tests in watch mode: `npm test`
|
||||
- Check console output for specific error messages
|
||||
|
||||
### Coverage not generating
|
||||
|
||||
- Ensure you're using the `--code-coverage` flag
|
||||
- Check that all test files end with `.spec.ts`
|
||||
|
||||
## Contributing
|
||||
|
||||
When adding new features:
|
||||
|
||||
1. Write tests first (TDD approach)
|
||||
2. Ensure all tests pass
|
||||
3. Maintain high code coverage
|
||||
|
||||
@@ -5,12 +5,14 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
## Test Files Created/Updated
|
||||
|
||||
### 1. **App Component Tests** (`src/app/app.spec.ts`)
|
||||
|
||||
- ✅ Component creation
|
||||
- ✅ ImagePreloadService injection
|
||||
- ✅ Champion randomizer component rendering
|
||||
- ✅ Toolbar rendering
|
||||
|
||||
### 2. **Champion Randomizer Component Tests** (`src/app/components/champion-randomizer.component.spec.ts`)
|
||||
|
||||
- ✅ Component creation and initialization
|
||||
- ✅ Lane management (enable/disable lanes)
|
||||
- ✅ Champion assignment and rolling
|
||||
@@ -26,6 +28,7 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
- ✅ Shift key tracking for force rerolls
|
||||
|
||||
### 3. **Control Header Component Tests** (`src/app/components/control-header/control-header.component.spec.ts`)
|
||||
|
||||
- ✅ Component creation
|
||||
- ✅ All input properties (isLoading, hasChampions, loadError, canCopyDraft, rerollBank, rerollBankMax)
|
||||
- ✅ Output events (roll, retry, copyDraft)
|
||||
@@ -33,6 +36,7 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
- ✅ Template rendering (spinner, error messages)
|
||||
|
||||
### 4. **Lane Card Component Tests** (`src/app/components/lane-card/lane-card.component.spec.ts`)
|
||||
|
||||
- ✅ Component creation
|
||||
- ✅ All input properties (lane, laneLabel, champion, canReRoll, isLoading, hasChampions, isShiftPressed, disabled)
|
||||
- ✅ Output events (changeChampion, toggleDisableLane)
|
||||
@@ -40,6 +44,7 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
- ✅ Template rendering (champion name, image, lane label, role chips, disabled styling)
|
||||
|
||||
### 5. **Champion Data Service Tests** (`src/app/services/champion-data.service.spec.ts`)
|
||||
|
||||
- ✅ Service creation
|
||||
- ✅ Loading champions from API
|
||||
- ✅ HTTP to HTTPS URL conversion
|
||||
@@ -58,11 +63,13 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
- ✅ Invalid cache data handling
|
||||
|
||||
### 6. **Image Preload Service Tests** (`src/app/services/image-preload.service.spec.ts`)
|
||||
|
||||
- ✅ Service creation
|
||||
- ✅ Cache clearing functionality
|
||||
- ✅ Error handling during cache operations
|
||||
|
||||
### 7. **Random Number Service Tests** (`src/app/services/random-number.spec.ts`)
|
||||
|
||||
- ✅ Service creation
|
||||
- ✅ Random number generation within range
|
||||
- ✅ Edge case: max = 1
|
||||
@@ -73,12 +80,14 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
- ✅ crypto.getRandomValues usage verification
|
||||
|
||||
### 8. **Preload Link Directive Tests** (`src/app/directives/preload-link.directive.spec.ts`)
|
||||
|
||||
- ✅ Directive creation
|
||||
- ✅ Preload link addition to document head
|
||||
- ✅ Fetchpriority attribute setting
|
||||
- ✅ Duplicate link prevention
|
||||
|
||||
### 9. **Image Cache Interceptor Tests** (`src/app/interceptors/image-cache.interceptor.spec.ts`)
|
||||
|
||||
- ✅ Cache header addition for PNG images
|
||||
- ✅ Cache header addition for JPG images
|
||||
- ✅ Cache header addition for JPEG images
|
||||
@@ -93,6 +102,7 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
## Test Statistics
|
||||
|
||||
### Total Test Suites: 9
|
||||
|
||||
- App: 4 tests
|
||||
- Champion Randomizer: 29 tests
|
||||
- Control Header: 10 tests
|
||||
@@ -108,20 +118,24 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
## Coverage Areas
|
||||
|
||||
### ✅ Components (100%)
|
||||
|
||||
- App
|
||||
- ChampionRandomizerComponent
|
||||
- ControlHeaderComponent
|
||||
- LaneCardComponent
|
||||
|
||||
### ✅ Services (100%)
|
||||
|
||||
- ChampionDataService
|
||||
- ImagePreloadService
|
||||
- RandomNumber
|
||||
|
||||
### ✅ Directives (100%)
|
||||
|
||||
- PreloadLinkDirective
|
||||
|
||||
### ✅ Interceptors (100%)
|
||||
|
||||
- imageCacheInterceptor
|
||||
|
||||
## Key Testing Features
|
||||
@@ -138,16 +152,19 @@ This document provides an overview of all the tests created for the Random LOL a
|
||||
## Running the Tests
|
||||
|
||||
To run all tests:
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
To run tests in headless mode (requires Chrome):
|
||||
|
||||
```bash
|
||||
npm test -- --watch=false --browsers=ChromeHeadless
|
||||
```
|
||||
|
||||
To run tests with coverage:
|
||||
|
||||
```bash
|
||||
ng test --no-watch --code-coverage
|
||||
```
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
|
||||
.warning-card mat-icon {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,18 @@
|
||||
></app-control-header>
|
||||
<div class="lane-grid">
|
||||
@for (assignment of laneAssignments(); track assignment.lane) {
|
||||
<app-lane-card
|
||||
[lane]="assignment.lane"
|
||||
[laneLabel]="laneLabel(assignment.lane)"
|
||||
[champion]="assignment.champion"
|
||||
[canReRoll]="reRollBank() > 0"
|
||||
[isLoading]="isLoading()"
|
||||
[hasChampions]="hasChampions()"
|
||||
[isShiftPressed]="isShiftPressed()"
|
||||
[disabled]="disabledLanes().has(assignment.lane)"
|
||||
(changeChampion)="changeChampion($event.lane, $event.forceReroll)"
|
||||
(toggleDisableLane)="toggleLane($event)"
|
||||
></app-lane-card>
|
||||
<app-lane-card
|
||||
[lane]="assignment.lane"
|
||||
[laneLabel]="laneLabel(assignment.lane)"
|
||||
[champion]="assignment.champion"
|
||||
[canReRoll]="reRollBank() > 0"
|
||||
[isLoading]="isLoading()"
|
||||
[hasChampions]="hasChampions()"
|
||||
[isShiftPressed]="isShiftPressed()"
|
||||
[disabled]="disabledLanes().has(assignment.lane)"
|
||||
(changeChampion)="changeChampion($event.lane, $event.forceReroll)"
|
||||
(toggleDisableLane)="toggleLane($event)"
|
||||
></app-lane-card>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
@@ -66,7 +66,7 @@ describe('ChampionRandomizerComponent', () => {
|
||||
championsByLane: championsByLaneSignal.asReadonly(),
|
||||
loading: loadingSignal.asReadonly(),
|
||||
error: errorSignal.asReadonly(),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
championDataSpy.ensureLoaded.and.returnValue(Promise.resolve());
|
||||
@@ -83,7 +83,7 @@ describe('ChampionRandomizerComponent', () => {
|
||||
}).compileComponents();
|
||||
|
||||
championDataService = TestBed.inject(
|
||||
ChampionDataService
|
||||
ChampionDataService,
|
||||
) as jasmine.SpyObj<ChampionDataService>;
|
||||
fixture = TestBed.createComponent(ChampionRandomizerComponent);
|
||||
component = fixture.componentInstance;
|
||||
@@ -230,7 +230,7 @@ describe('ChampionRandomizerComponent', () => {
|
||||
['mid', null],
|
||||
['adc', null],
|
||||
['support', null],
|
||||
])
|
||||
]),
|
||||
);
|
||||
|
||||
// Set reroll bank to 0.5 (less than 1)
|
||||
@@ -286,7 +286,7 @@ describe('ChampionRandomizerComponent', () => {
|
||||
['mid', mockChampions[1]],
|
||||
['adc', mockChampions[2]],
|
||||
['support', mockChampions[3]],
|
||||
])
|
||||
]),
|
||||
);
|
||||
|
||||
expect(component['canCopyDraft']()).toBe(true);
|
||||
@@ -339,7 +339,7 @@ describe('ChampionRandomizerComponent', () => {
|
||||
}
|
||||
|
||||
spyOn(navigator.clipboard, 'writeText').and.returnValue(
|
||||
Promise.reject(new Error('Clipboard error'))
|
||||
Promise.reject(new Error('Clipboard error')),
|
||||
);
|
||||
spyOn(console, 'error');
|
||||
component['rollAssignments']();
|
||||
|
||||
@@ -63,7 +63,7 @@ export class ChampionRandomizerComponent {
|
||||
protected readonly hasChampions = computed(() => this.champions().length > 0);
|
||||
|
||||
protected readonly assignments = signal<Map<Lane, Champion | null>>(
|
||||
this.createEmptyAssignments()
|
||||
this.createEmptyAssignments(),
|
||||
);
|
||||
|
||||
protected readonly disabledLanesArray = computed(() => {
|
||||
@@ -104,8 +104,8 @@ export class ChampionRandomizerComponent {
|
||||
(champion) =>
|
||||
!this.assignmentsArray().some(
|
||||
(assignedChampion) =>
|
||||
assignedChampion && assignedChampion.name === champion.name
|
||||
)
|
||||
assignedChampion && assignedChampion.name === champion.name,
|
||||
),
|
||||
) || [];
|
||||
notUsed.set(lane, champion);
|
||||
}
|
||||
@@ -125,7 +125,7 @@ export class ChampionRandomizerComponent {
|
||||
champion,
|
||||
rolesText,
|
||||
} satisfies LaneAssignmentView;
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
protected readonly canCopyDraft = computed<boolean>(() => {
|
||||
@@ -185,7 +185,7 @@ export class ChampionRandomizerComponent {
|
||||
|
||||
for (const lane of this.activatedLanesArray()) {
|
||||
const candidates = (championsByLaneMap.get(lane) || []).filter(
|
||||
(champion: Champion) => !selected.has(champion.name)
|
||||
(champion: Champion) => !selected.has(champion.name),
|
||||
);
|
||||
|
||||
if (candidates.length === 0) {
|
||||
|
||||
@@ -36,18 +36,18 @@
|
||||
<span class="centered-text">{{ rerollBank() }}</span>
|
||||
</div>
|
||||
@if (isLoading()) {
|
||||
<div class="status mat-body-small" aria-live="polite">
|
||||
<mat-icon aria-hidden="true">autorenew</mat-icon>
|
||||
<span>Loading champion data…</span>
|
||||
</div>
|
||||
<div class="status mat-body-small" aria-live="polite">
|
||||
<mat-icon aria-hidden="true">autorenew</mat-icon>
|
||||
<span>Loading champion data…</span>
|
||||
</div>
|
||||
} @else if (loadError(); as errorMessage) {
|
||||
<div class="status error mat-body-small" aria-live="polite">
|
||||
<mat-icon aria-hidden="true" color="warn">error</mat-icon>
|
||||
<span>{{ errorMessage }}</span>
|
||||
<button type="button" mat-button color="accent" (click)="onRetry()">
|
||||
<mat-icon aria-hidden="true">refresh</mat-icon>
|
||||
<span>Retry</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="status error mat-body-small" aria-live="polite">
|
||||
<mat-icon aria-hidden="true" color="warn">error</mat-icon>
|
||||
<span>{{ errorMessage }}</span>
|
||||
<button type="button" mat-button color="accent" (click)="onRetry()">
|
||||
<mat-icon aria-hidden="true">refresh</mat-icon>
|
||||
<span>Retry</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</header>
|
||||
@@ -72,7 +72,6 @@
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
@@ -132,4 +131,4 @@
|
||||
|
||||
.enable-lane-button {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +1,114 @@
|
||||
@if (disabled()) {
|
||||
<mat-card class="lane-card disabled-card">
|
||||
<mat-card-header class="mat-header">
|
||||
<mat-card-title-group>
|
||||
<mat-card-title>{{ laneLabel() }}</mat-card-title>
|
||||
<mat-card-subtitle>Lane currently disabled</mat-card-subtitle>
|
||||
</mat-card-title-group>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="disabled-message">
|
||||
<mat-icon class="disabled-icon" aria-hidden="true">block</mat-icon>
|
||||
<p class="mat-body-large">This lane has been disabled</p>
|
||||
<p class="mat-body-small">You chose to exclude this lane from the random selection.</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
matFab
|
||||
extended
|
||||
color="primary"
|
||||
class="enable-lane-button"
|
||||
(click)="onToggleDisableLane()"
|
||||
>
|
||||
<mat-icon aria-hidden="true">add_circle</mat-icon>
|
||||
Enable Lane
|
||||
</button>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="lane-card disabled-card">
|
||||
<mat-card-header class="mat-header">
|
||||
<mat-card-title-group>
|
||||
<mat-card-title>{{ laneLabel() }}</mat-card-title>
|
||||
<mat-card-subtitle>Lane currently disabled</mat-card-subtitle>
|
||||
</mat-card-title-group>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="disabled-message">
|
||||
<mat-icon class="disabled-icon" aria-hidden="true">block</mat-icon>
|
||||
<p class="mat-body-large">This lane has been disabled</p>
|
||||
<p class="mat-body-small">
|
||||
You chose to exclude this lane from the random selection.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
matFab
|
||||
extended
|
||||
color="primary"
|
||||
class="enable-lane-button"
|
||||
(click)="onToggleDisableLane()"
|
||||
>
|
||||
<mat-icon aria-hidden="true">add_circle</mat-icon>
|
||||
Enable Lane
|
||||
</button>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
} @else {
|
||||
<mat-card class="lane-card">
|
||||
<mat-card-header class="mat-header">
|
||||
<mat-card-title-group>
|
||||
<mat-card-title>{{ laneLabel() }}</mat-card-title>
|
||||
<mat-card-subtitle>
|
||||
{{ champion() ? 'Unique pick locked in' : 'Champion needed for this lane' }}
|
||||
</mat-card-subtitle>
|
||||
</mat-card-title-group>
|
||||
<button
|
||||
matMiniFab
|
||||
[disabled]="isLoading() || !hasChampions()"
|
||||
(click)="onToggleDisableLane()"
|
||||
>
|
||||
<mat-icon aria-hidden="true">close</mat-icon>
|
||||
</button>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
@if (champion(); as champ) {
|
||||
<div class="champion-details">
|
||||
<img
|
||||
[ngSrc]="champ.icon"
|
||||
width="96"
|
||||
height="96"
|
||||
[class.loading-image]="isLoading()"
|
||||
[alt]="champ.name + ' portrait'"
|
||||
[priority]="true"
|
||||
class="champion-icon"
|
||||
/>
|
||||
<p class="champion-name mat-title-medium">{{ champ.name }}</p>
|
||||
</div>
|
||||
<mat-chip-set class="roles-set" [attr.aria-label]="'Roles for ' + champ.name">
|
||||
@for (role of champ.roles; track role) {
|
||||
<mat-chip>{{ roleLabel(role) }}</mat-chip>
|
||||
}
|
||||
</mat-chip-set>
|
||||
} @else {
|
||||
<p class="champion-name champion-name-empty mat-title-medium">No champion available</p>
|
||||
<p class="champion-roles mat-body-small">Roll again once champions finish loading.</p>
|
||||
} @if (canReRoll()) {
|
||||
<button
|
||||
type="button"
|
||||
matFab
|
||||
extended
|
||||
color="accent"
|
||||
class="change-champion-button"
|
||||
[disabled]="isLoading() || !hasChampions()"
|
||||
(click)="onChangeChampion(false)"
|
||||
>
|
||||
<mat-icon aria-hidden="true">refresh</mat-icon>
|
||||
Re-Roll !
|
||||
</button>
|
||||
} @else {
|
||||
<button
|
||||
type="button"
|
||||
matFab
|
||||
extended
|
||||
color="accent"
|
||||
class="change-champion-button"
|
||||
[disabled]="isLoading() || !hasChampions() || (!isShiftPressed() && !canReRoll())"
|
||||
(click)="onChangeChampion(isShiftPressed())"
|
||||
[class.shift-active]="isShiftPressed()"
|
||||
>
|
||||
@if (!isShiftPressed()) {
|
||||
<mat-icon aria-hidden="true">heart_broken</mat-icon>
|
||||
<mat-card class="lane-card">
|
||||
<mat-card-header class="mat-header">
|
||||
<mat-card-title-group>
|
||||
<mat-card-title>{{ laneLabel() }}</mat-card-title>
|
||||
<mat-card-subtitle>
|
||||
{{ champion() ? 'Unique pick locked in' : 'Champion needed for this lane' }}
|
||||
</mat-card-subtitle>
|
||||
</mat-card-title-group>
|
||||
<button
|
||||
matMiniFab
|
||||
[disabled]="isLoading() || !hasChampions()"
|
||||
(click)="onToggleDisableLane()"
|
||||
>
|
||||
<mat-icon aria-hidden="true">close</mat-icon>
|
||||
</button>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
@if (champion(); as champ) {
|
||||
<div class="champion-details">
|
||||
<img
|
||||
[ngSrc]="champ.icon"
|
||||
width="96"
|
||||
height="96"
|
||||
[class.loading-image]="isLoading()"
|
||||
[alt]="champ.name + ' portrait'"
|
||||
[priority]="true"
|
||||
class="champion-icon"
|
||||
/>
|
||||
<p class="champion-name mat-title-medium">{{ champ.name }}</p>
|
||||
</div>
|
||||
<mat-chip-set class="roles-set" [attr.aria-label]="'Roles for ' + champ.name">
|
||||
@for (role of champ.roles; track role) {
|
||||
<mat-chip>{{ roleLabel(role) }}</mat-chip>
|
||||
}
|
||||
</mat-chip-set>
|
||||
} @else {
|
||||
<mat-icon aria-hidden="true">lock_open_right</mat-icon>
|
||||
} @if (!isShiftPressed()) {
|
||||
<p>No re-rolls left</p>
|
||||
} @else {
|
||||
<p>Force Re-Roll!</p>
|
||||
<p class="champion-name champion-name-empty mat-title-medium">
|
||||
No champion available
|
||||
</p>
|
||||
<p class="champion-roles mat-body-small">
|
||||
Roll again once champions finish loading.
|
||||
</p>
|
||||
}
|
||||
</button>
|
||||
}
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@if (canReRoll()) {
|
||||
<button
|
||||
type="button"
|
||||
matFab
|
||||
extended
|
||||
color="accent"
|
||||
class="change-champion-button"
|
||||
[disabled]="isLoading() || !hasChampions()"
|
||||
(click)="onChangeChampion(false)"
|
||||
>
|
||||
<mat-icon aria-hidden="true">refresh</mat-icon>
|
||||
Re-Roll !
|
||||
</button>
|
||||
} @else {
|
||||
<button
|
||||
type="button"
|
||||
matFab
|
||||
extended
|
||||
color="accent"
|
||||
class="change-champion-button"
|
||||
[disabled]="
|
||||
isLoading() || !hasChampions() || (!isShiftPressed() && !canReRoll())
|
||||
"
|
||||
(click)="onChangeChampion(isShiftPressed())"
|
||||
[class.shift-active]="isShiftPressed()"
|
||||
>
|
||||
@if (!isShiftPressed()) {
|
||||
<mat-icon aria-hidden="true">heart_broken</mat-icon>
|
||||
} @else {
|
||||
<mat-icon aria-hidden="true">lock_open_right</mat-icon>
|
||||
}
|
||||
@if (!isShiftPressed()) {
|
||||
<p>No re-rolls left</p>
|
||||
} @else {
|
||||
<p>Force Re-Roll!</p>
|
||||
}
|
||||
</button>
|
||||
}
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
@@ -34,7 +34,7 @@ describe('PreloadLinkDirective', () => {
|
||||
setTimeout(() => {
|
||||
const preloadLinks = document.querySelectorAll('link[rel="preload"][as="image"]');
|
||||
const hasTestLink = Array.from(preloadLinks).some((link) =>
|
||||
link.getAttribute('href')?.includes('test.png')
|
||||
link.getAttribute('href')?.includes('test.png'),
|
||||
);
|
||||
expect(hasTestLink).toBe(true);
|
||||
done();
|
||||
@@ -47,10 +47,10 @@ describe('PreloadLinkDirective', () => {
|
||||
|
||||
setTimeout(() => {
|
||||
const preloadLinks = document.querySelectorAll(
|
||||
'link[rel="preload"][as="image"][fetchpriority="high"]'
|
||||
'link[rel="preload"][as="image"][fetchpriority="high"]',
|
||||
);
|
||||
const hasTestLink = Array.from(preloadLinks).some((link) =>
|
||||
link.getAttribute('href')?.includes('test.png')
|
||||
link.getAttribute('href')?.includes('test.png'),
|
||||
);
|
||||
expect(hasTestLink).toBe(true);
|
||||
done();
|
||||
@@ -66,7 +66,7 @@ describe('PreloadLinkDirective', () => {
|
||||
|
||||
setTimeout(() => {
|
||||
const preloadLinks = document.querySelectorAll(
|
||||
'link[rel="preload"][href="https://example.com/test.png"]'
|
||||
'link[rel="preload"][href="https://example.com/test.png"]',
|
||||
);
|
||||
// Should only have one link, not duplicates
|
||||
expect(preloadLinks.length).toBeLessThanOrEqual(1);
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('imageCacheInterceptor', () => {
|
||||
.subscribe();
|
||||
|
||||
const req = httpMock.expectOne(
|
||||
'https://ddragon.leagueoflegends.com/cdn/14.1.1/img/champion/Aatrox.png'
|
||||
'https://ddragon.leagueoflegends.com/cdn/14.1.1/img/champion/Aatrox.png',
|
||||
);
|
||||
expect(req.request.headers.get('Cache-Control')).toBe('public, max-age=86400, immutable');
|
||||
req.flush({});
|
||||
|
||||
@@ -194,7 +194,7 @@ describe('ChampionDataService', () => {
|
||||
const champions = service.champions();
|
||||
for (let i = 1; i < champions.length; i++) {
|
||||
expect(champions[i - 1].name.localeCompare(champions[i].name)).toBeLessThanOrEqual(
|
||||
0
|
||||
0,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -134,7 +134,7 @@ export class ChampionDataService {
|
||||
|
||||
try {
|
||||
const response = await firstValueFrom(
|
||||
this.http.get<Record<string, RemoteChampion>>(CHAMPION_DATA_URL)
|
||||
this.http.get<Record<string, RemoteChampion>>(CHAMPION_DATA_URL),
|
||||
);
|
||||
|
||||
const champions = Object.entries(response)
|
||||
@@ -174,8 +174,8 @@ export class ChampionDataService {
|
||||
new Set(
|
||||
data.positions
|
||||
.map((position) => POSITION_TO_LANE[position])
|
||||
.filter((role): role is Lane => role !== undefined)
|
||||
)
|
||||
.filter((role): role is Lane => role !== undefined),
|
||||
),
|
||||
);
|
||||
|
||||
if (roles.length === 0 || !data.icon) {
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('ImagePreloadService', () => {
|
||||
});
|
||||
|
||||
championDataService = TestBed.inject(
|
||||
ChampionDataService
|
||||
ChampionDataService,
|
||||
) as jasmine.SpyObj<ChampionDataService>;
|
||||
service = TestBed.inject(ImagePreloadService);
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('RandomNumber', () => {
|
||||
|
||||
it('should throw RangeError for max > Number.MAX_SAFE_INTEGER', () => {
|
||||
expect(() => RandomNumber.getSecureRandomInt(Number.MAX_SAFE_INTEGER + 1)).toThrowError(
|
||||
RangeError
|
||||
RangeError,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user