Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Time To Opponent #97

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
<div>
<div class="tile"
[ngStyle]="getBackgroundColor()">
<p id="remainingTime"
class="remainingTimeText"
[ngStyle]="getTimeStyle()">{{ displayedMinute }}:{{ displayedSec | number:'2.0-0' }}</p>
<button id="addTimeButton"
class="button is-small remainingTimeButton"
[ngStyle]="getBackgroundColor()"
*ngIf="canAddTime"
(click)="addTime()"
> + </button>
</div>
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { DebugElement } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { fakeAsync, tick } from '@angular/core/testing';
import { SimpleComponentTestUtils } from 'src/app/utils/tests/TestUtils.spec';
import { CountDownComponent } from './count-down.component';

describe('CountDownComponent', () => {

let component: CountDownComponent;
let testUtils: SimpleComponentTestUtils<CountDownComponent>;

let fixture: ComponentFixture<CountDownComponent>;
let component: CountDownComponent;

beforeEach(fakeAsync(async() => {
await TestBed.configureTestingModule({
declarations: [CountDownComponent],
}).compileComponents();
fixture = TestBed.createComponent(CountDownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
testUtils = await SimpleComponentTestUtils.create(CountDownComponent);
component = testUtils.getComponent();
}));
it('should create', () => {
expect(component).toBeTruthy();
Expand All @@ -40,14 +36,15 @@ describe('CountDownComponent', () => {
});
it('should show remaining time once set', () => {
component.setDuration(62000);
fixture.detectChanges();
const element: DebugElement = fixture.debugElement.query(By.css('#remainingTime'));
testUtils.detectChanges();
const element: DebugElement = testUtils.findElement('#remainingTime');
const timeText: string = element.nativeElement.innerHTML;
expect(timeText).toBe('1:02');
});
it('should throw when starting stopped chrono again', () => {
component.setDuration(1250);
component.start();
expect(component.isStarted()).toBeTrue();
component.stop();
expect(() => component.start()).toThrowError('Should not start a chrono that has not been set!');
});
Expand Down Expand Up @@ -92,34 +89,34 @@ describe('CountDownComponent', () => {
component.setDuration(3000);
component.start();
tick(1000);
fixture.detectChanges();
let timeText: string = fixture.debugElement.query(By.css('#remainingTime')).nativeElement.innerHTML;
testUtils.detectChanges();
let timeText: string = testUtils.findElement('#remainingTime').nativeElement.innerHTML;
expect(timeText).toBe('0:02');
tick(1000);
fixture.detectChanges();
timeText = fixture.debugElement.query(By.css('#remainingTime')).nativeElement.innerHTML;
testUtils.detectChanges();
timeText = testUtils.findElement('#remainingTime').nativeElement.innerHTML;
expect(timeText).toBe('0:01');
component.stop();
}));
it('should update written time correctly (closest rounding) even when playing in less than refreshing time', fakeAsync(() => {
spyOn(component.outOfTimeAction, 'emit').and.callThrough();
component.setDuration(599501); // 9 minutes 59 sec 501 ms
fixture.detectChanges();
let timeText: string = fixture.debugElement.query(By.css('#remainingTime')).nativeElement.innerHTML;
testUtils.detectChanges();
let timeText: string = testUtils.findElement('#remainingTime').nativeElement.innerHTML;
expect(timeText).toBe('9:59');
component.start();

tick(401); // 9 min 59.501s -> 9 min 59.1 (9:59)
component.pause();
fixture.detectChanges();
timeText = fixture.debugElement.query(By.css('#remainingTime')).nativeElement.innerHTML;
testUtils.detectChanges();
timeText = testUtils.findElement('#remainingTime').nativeElement.innerHTML;
expect(timeText).toBe('9:59');

component.resume();
tick(200); // 9 min 59.1 -> 9 min 58.9 (9:58)
component.pause();
fixture.detectChanges();
timeText = fixture.debugElement.query(By.css('#remainingTime')).nativeElement.innerHTML;
testUtils.detectChanges();
timeText = testUtils.findElement('#remainingTime').nativeElement.innerHTML;
expect(timeText).toBe('9:58');
}));
it('should emit when timeout reached', fakeAsync(() => {
Expand All @@ -131,21 +128,44 @@ describe('CountDownComponent', () => {
tick(1000);
expect(component.outOfTimeAction.emit).toHaveBeenCalledOnceWith();
}));
describe('Add Time Button', () => {
it('should offer opportunity to add time if allowed', fakeAsync(async() => {
// Given a CountDownComponent allowed to add time, with 1 minute remaining
component.canAddTime = true;
component.remainingMs = 60 * 1000;
testUtils.detectChanges();

// when clicking the add time button
spyOn(component.addTimeToOpponent, 'emit').and.callThrough();
await testUtils.clickElement('#addTimeButton');

// the component should have called addTimeToOpponent
expect(component.addTimeToOpponent.emit).toHaveBeenCalledOnceWith();
}));
it('should not display button when not allowed to add time', fakeAsync(async() => {
// given a CountDownComponent not allowed to add time
component.canAddTime = false;
testUtils.detectChanges();

// the component should not have that button
testUtils.expectElementNotToExist('#addTimeButton');
}));
});
describe('Style depending of remaining time', () => {
it('Should be safe style when upper than limit', () => {
component.dangerTimeLimit = 10 * 1000;
component.setDuration(12 * 1000);
expect(component.getTimeStyle()).toEqual(component.SAFE_TIME);
expect(component.getTimeStyle()).toEqual(CountDownComponent.SAFE_TIME);
});
it('Should be first danger style when lower than limit and even remaining second', () => {
component.dangerTimeLimit = 10 * 1000;
component.setDuration(9 * 1000);
expect(component.getTimeStyle()).toEqual(component.DANGER_TIME_EVEN);
expect(component.getTimeStyle()).toEqual(CountDownComponent.DANGER_TIME_EVEN);
});
it('Should be second danger style when lower than limit and odd remaining second', () => {
component.dangerTimeLimit = 10 * 1000;
component.setDuration(8 * 1000);
expect(component.getTimeStyle()).toEqual(component.DANGER_TIME_ODD);
expect(component.getTimeStyle()).toEqual(CountDownComponent.DANGER_TIME_ODD);
});
it('Should be in passive style when passive', () => {
// given a chrono that could be in danger time style
Expand All @@ -155,7 +175,7 @@ describe('CountDownComponent', () => {
component.active = false;

// then it should still be in passive style
expect(component.getTimeStyle()).toEqual(component.PASSIVE_STYLE);
expect(component.getTimeStyle()).toEqual(CountDownComponent.PASSIVE_STYLE);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export class CountDownComponent implements OnInit, OnDestroy {
@Input() debugName: string;
@Input() dangerTimeLimit: number;
@Input() active: boolean;
@Input() canAddTime: boolean;

public remainingMs: number;
public displayedSec: number;
Expand All @@ -24,24 +25,25 @@ export class CountDownComponent implements OnInit, OnDestroy {
private startTime: number;

@Output() outOfTimeAction: EventEmitter<void> = new EventEmitter<void>();
@Output() addTimeToOpponent: EventEmitter<void> = new EventEmitter<void>();

public readonly DANGER_TIME_EVEN: { [key: string]: string } = {
public static readonly DANGER_TIME_EVEN: { [key: string]: string } = {
'color': 'red',
'font-weight': 'bold',
};
public readonly DANGER_TIME_ODD: { [key: string]: string } = {
public static readonly DANGER_TIME_ODD: { [key: string]: string } = {
'color': 'white',
'font-weight': 'bold',
'background-color': 'red',
};
public readonly PASSIVE_STYLE: { [key: string]: string } = {
public static readonly PASSIVE_STYLE: { [key: string]: string } = {
'color': 'lightgrey',
'background-color': 'darkgrey',
'font-size': 'italic',
};
public readonly SAFE_TIME: { [key: string]: string } = { color: 'black' };
public static readonly SAFE_TIME: { [key: string]: string } = { color: 'black' };

public style: { [key: string]: string } = this.SAFE_TIME;
public style: { [key: string]: string } = CountDownComponent.SAFE_TIME;

public ngOnInit(): void {
display(CountDownComponent.VERBOSE, 'CountDownComponent.ngOnInit (' + this.debugName + ')');
Expand All @@ -56,9 +58,20 @@ export class CountDownComponent implements OnInit, OnDestroy {
this.changeDuration(duration);
}
public changeDuration(ms: number): void {
let mustResume: boolean = false;
if (this.isPaused === false) {
this.pause();
mustResume = true;
}
this.remainingMs = ms;
this.displayedSec = ms % (60 * 1000);
this.displayedMinute = (ms - this.displayedSec) / (60 * 1000);
this.displayDuration();
if (mustResume) {
this.resume();
}
}
private displayDuration(): void {
this.displayedSec = this.remainingMs % (60 * 1000);
this.displayedMinute = (this.remainingMs - this.displayedSec) / (60 * 1000);
this.displayedSec = Math.floor(this.displayedSec / 1000);
}
public start(): void {
Expand Down Expand Up @@ -134,25 +147,29 @@ export class CountDownComponent implements OnInit, OnDestroy {
}
public getTimeStyle(): { [key: string]: string } {
if (this.active === false) {
return this.PASSIVE_STYLE;
return CountDownComponent.PASSIVE_STYLE;
}
if (this.remainingMs < this.dangerTimeLimit) {
if (this.remainingMs % 2000 < 1000) {
return this.DANGER_TIME_ODD;
return CountDownComponent.DANGER_TIME_ODD;
} else {
return this.DANGER_TIME_EVEN;
return CountDownComponent.DANGER_TIME_EVEN;
}
} else {
return this.SAFE_TIME;
return CountDownComponent.SAFE_TIME;
}
}
public getBackgroundColor(): { [key: string]: string } {
const buttonStyle: { [key: string]: string } = this.getTimeStyle();
return { 'background-color': buttonStyle['background-color'] };
}
private updateShownTime(): void {
const now: number = Date.now();
this.remainingMs -= (now - this.startTime);
this.changeDuration(this.remainingMs);
this.displayDuration();
this.style = this.getTimeStyle();
this.startTime = now;
if (!this.isPaused) {
if (this.isPaused === false) {
this.countSeconds();
}
}
Expand All @@ -168,4 +185,7 @@ export class CountDownComponent implements OnInit, OnDestroy {
public ngOnDestroy(): void {
this.clearTimeouts();
}
public addTime(): void {
this.addTimeToOpponent.emit();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@
<app-count-down #chronoZeroGlobal
[dangerTimeLimit]="60*1000"
[active]="(currentPart == null) ? false : currentPart.getTurn() % 2 === 0"
[canAddTime]='observerRole === 1 && endGame === false'
debugName="ZERO Global"
(outOfTimeAction)="reachedOutOfTime(0)">
(outOfTimeAction)="reachedOutOfTime(0)"
(addTimeToOpponent)="addGlobalTime()">
</app-count-down>
<app-count-down #chronoZeroLocal
[dangerTimeLimit]="15*1000"
[active]="(currentPart == null) ? false : currentPart.getTurn() % 2 === 0"
[canAddTime]='observerRole === 1 && endGame === false'
debugName="ZERO Local"
(outOfTimeAction)="reachedOutOfTime(0)">
(outOfTimeAction)="reachedOutOfTime(0)"
(addTimeToOpponent)="addLocalTime()">
</app-count-down>
</div>
<p class="is-size-3" i18n>vs.</p>
Expand All @@ -42,14 +46,18 @@
<app-count-down #chronoOneGlobal
[dangerTimeLimit]="60*1000"
[active]="(currentPart == null) ? false : currentPart.getTurn() % 2 === 1"
[canAddTime]='observerRole === 0 && endGame === false'
debugName="ONE Global"
(outOfTimeAction)="reachedOutOfTime(1)">
(outOfTimeAction)="reachedOutOfTime(1)"
(addTimeToOpponent)="addGlobalTime()">
</app-count-down>
<app-count-down #chronoOneLocal
[dangerTimeLimit]="15*1000"
[active]="(currentPart == null) ? false : currentPart.getTurn() % 2 === 1"
[canAddTime]='observerRole === 0 && endGame === false'
debugName="ONE Local"
(outOfTimeAction)="reachedOutOfTime(1)">
(outOfTimeAction)="reachedOutOfTime(1)"
(addTimeToOpponent)="addLocalTime()">
</app-count-down>
</div>
<hr/>
Expand Down Expand Up @@ -105,7 +113,8 @@
<div class="block" id="winnerIndicator" *ngIf="endGame">
<hr/>
<div *ngIf="currentPart.isDraw()">
<p class="title" *ngIf="currentPart.getWinner() == null" i18n>Draw</p>
<p class="title" id="hardDrawIndicator" *ngIf="currentPart.isHardDraw()" i18n>Draw</p>
<p class="title" id="agreedDrawIndicator" *ngIf="currentPart.isAgreedDraw()" i18n>You agreed to draw</p>
</div>
<div *ngIf="currentPart.isWin()">
<p class="title" id="youWonIndicator" *ngIf="currentPart.getWinner() === userName" i18n>You won.</p>
Expand Down
Loading