feat: Implement tasks feature using NGRX signals and remove the old counter store, alongside general project configuration and skill documentation updates.
continuous-integration/drone/pr Build is passing
continuous-integration/drone/pr Build is passing
This commit is contained in:
@@ -19,19 +19,19 @@ Configure in angular.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"projects": {
|
||||
"your-app": {
|
||||
"architect": {
|
||||
"test": {
|
||||
"builder": "@angular/build:unit-test",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"buildTarget": "your-app:build"
|
||||
}
|
||||
"projects": {
|
||||
"your-app": {
|
||||
"architect": {
|
||||
"test": {
|
||||
"builder": "@angular/build:unit-test",
|
||||
"options": {
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"buildTarget": "your-app:build"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -48,41 +48,41 @@ For Vitest migration from Jasmine and advanced configuration, see [references/vi
|
||||
## Basic Component Test
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect, beforeEach } from "vitest";
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { Counter } from "./counter.component";
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Counter } from './counter.component';
|
||||
|
||||
describe("Counter", () => {
|
||||
let component: Counter;
|
||||
let fixture: ComponentFixture<Counter>;
|
||||
describe('Counter', () => {
|
||||
let component: Counter;
|
||||
let fixture: ComponentFixture<Counter>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Counter], // Standalone component
|
||||
}).compileComponents();
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [Counter], // Standalone component
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(Counter);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
fixture = TestBed.createComponent(Counter);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should increment count", () => {
|
||||
expect(component.count()).toBe(0);
|
||||
component.increment();
|
||||
expect(component.count()).toBe(1);
|
||||
});
|
||||
it('should increment count', () => {
|
||||
expect(component.count()).toBe(0);
|
||||
component.increment();
|
||||
expect(component.count()).toBe(1);
|
||||
});
|
||||
|
||||
it("should display count in template", () => {
|
||||
component.count.set(5);
|
||||
fixture.detectChanges();
|
||||
it('should display count in template', () => {
|
||||
component.count.set(5);
|
||||
fixture.detectChanges();
|
||||
|
||||
const element = fixture.nativeElement.querySelector(".count");
|
||||
expect(element.textContent).toContain("5");
|
||||
});
|
||||
const element = fixture.nativeElement.querySelector('.count');
|
||||
expect(element.textContent).toContain('5');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -91,21 +91,21 @@ describe("Counter", () => {
|
||||
### Direct Signal Testing
|
||||
|
||||
```typescript
|
||||
import { signal, computed } from "@angular/core";
|
||||
import { signal, computed } from '@angular/core';
|
||||
|
||||
describe("Signal logic", () => {
|
||||
it("should update computed when signal changes", () => {
|
||||
const count = signal(0);
|
||||
const doubled = computed(() => count() * 2);
|
||||
describe('Signal logic', () => {
|
||||
it('should update computed when signal changes', () => {
|
||||
const count = signal(0);
|
||||
const doubled = computed(() => count() * 2);
|
||||
|
||||
expect(doubled()).toBe(0);
|
||||
expect(doubled()).toBe(0);
|
||||
|
||||
count.set(5);
|
||||
expect(doubled()).toBe(10);
|
||||
count.set(5);
|
||||
expect(doubled()).toBe(10);
|
||||
|
||||
count.update((c) => c + 1);
|
||||
expect(doubled()).toBe(12);
|
||||
});
|
||||
count.update((c) => c + 1);
|
||||
expect(doubled()).toBe(12);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -113,60 +113,60 @@ describe("Signal logic", () => {
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
selector: "app-todo-list",
|
||||
template: `
|
||||
<ul>
|
||||
@for (todo of filteredTodos(); track todo.id) {
|
||||
<li>{{ todo.text }}</li>
|
||||
}
|
||||
</ul>
|
||||
<p>{{ remaining() }} remaining</p>
|
||||
`,
|
||||
selector: 'app-todo-list',
|
||||
template: `
|
||||
<ul>
|
||||
@for (todo of filteredTodos(); track todo.id) {
|
||||
<li>{{ todo.text }}</li>
|
||||
}
|
||||
</ul>
|
||||
<p>{{ remaining() }} remaining</p>
|
||||
`,
|
||||
})
|
||||
export class TodoList {
|
||||
todos = signal<Todo[]>([]);
|
||||
filter = signal<"all" | "active" | "done">("all");
|
||||
todos = signal<Todo[]>([]);
|
||||
filter = signal<'all' | 'active' | 'done'>('all');
|
||||
|
||||
filteredTodos = computed(() => {
|
||||
const todos = this.todos();
|
||||
switch (this.filter()) {
|
||||
case "active":
|
||||
return todos.filter((t) => !t.done);
|
||||
case "done":
|
||||
return todos.filter((t) => t.done);
|
||||
default:
|
||||
return todos;
|
||||
}
|
||||
});
|
||||
filteredTodos = computed(() => {
|
||||
const todos = this.todos();
|
||||
switch (this.filter()) {
|
||||
case 'active':
|
||||
return todos.filter((t) => !t.done);
|
||||
case 'done':
|
||||
return todos.filter((t) => t.done);
|
||||
default:
|
||||
return todos;
|
||||
}
|
||||
});
|
||||
|
||||
remaining = computed(() => this.todos().filter((t) => !t.done).length);
|
||||
remaining = computed(() => this.todos().filter((t) => !t.done).length);
|
||||
}
|
||||
|
||||
describe("TodoList", () => {
|
||||
let component: TodoList;
|
||||
let fixture: ComponentFixture<TodoList>;
|
||||
describe('TodoList', () => {
|
||||
let component: TodoList;
|
||||
let fixture: ComponentFixture<TodoList>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TodoList],
|
||||
}).compileComponents();
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [TodoList],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TodoList);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
fixture = TestBed.createComponent(TodoList);
|
||||
component = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it("should filter active todos", () => {
|
||||
component.todos.set([
|
||||
{ id: "1", text: "Task 1", done: false },
|
||||
{ id: "2", text: "Task 2", done: true },
|
||||
{ id: "3", text: "Task 3", done: false },
|
||||
]);
|
||||
it('should filter active todos', () => {
|
||||
component.todos.set([
|
||||
{ id: '1', text: 'Task 1', done: false },
|
||||
{ id: '2', text: 'Task 2', done: true },
|
||||
{ id: '3', text: 'Task 3', done: false },
|
||||
]);
|
||||
|
||||
component.filter.set("active");
|
||||
component.filter.set('active');
|
||||
|
||||
expect(component.filteredTodos().length).toBe(2);
|
||||
expect(component.remaining()).toBe(2);
|
||||
});
|
||||
expect(component.filteredTodos().length).toBe(2);
|
||||
expect(component.remaining()).toBe(2);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -176,29 +176,29 @@ OnPush components require explicit change detection:
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `<span>{{ data().name }}</span>`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: `<span>{{ data().name }}</span>`,
|
||||
})
|
||||
export class OnPushCmpt {
|
||||
data = input.required<{ name: string }>();
|
||||
data = input.required<{ name: string }>();
|
||||
}
|
||||
|
||||
describe("OnPushCmpt", () => {
|
||||
it("should update when input signal changes", () => {
|
||||
const fixture = TestBed.createComponent(OnPushCmpt);
|
||||
describe('OnPushCmpt', () => {
|
||||
it('should update when input signal changes', () => {
|
||||
const fixture = TestBed.createComponent(OnPushCmpt);
|
||||
|
||||
// Set input using setInput (for signal inputs)
|
||||
fixture.componentRef.setInput("data", { name: "Initial" });
|
||||
fixture.detectChanges();
|
||||
// Set input using setInput (for signal inputs)
|
||||
fixture.componentRef.setInput('data', { name: 'Initial' });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.textContent).toContain("Initial");
|
||||
expect(fixture.nativeElement.textContent).toContain('Initial');
|
||||
|
||||
// Update input
|
||||
fixture.componentRef.setInput("data", { name: "Updated" });
|
||||
fixture.detectChanges();
|
||||
// Update input
|
||||
fixture.componentRef.setInput('data', { name: 'Updated' });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.textContent).toContain("Updated");
|
||||
});
|
||||
expect(fixture.nativeElement.textContent).toContain('Updated');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -207,72 +207,69 @@ describe("OnPushCmpt", () => {
|
||||
### Basic Service Test
|
||||
|
||||
```typescript
|
||||
@Injectable({ providedIn: "root" })
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CounterService {
|
||||
private _count = signal(0);
|
||||
readonly count = this._count.asReadonly();
|
||||
private _count = signal(0);
|
||||
readonly count = this._count.asReadonly();
|
||||
|
||||
increment() {
|
||||
this._count.update((c) => c + 1);
|
||||
}
|
||||
reset() {
|
||||
this._count.set(0);
|
||||
}
|
||||
increment() {
|
||||
this._count.update((c) => c + 1);
|
||||
}
|
||||
reset() {
|
||||
this._count.set(0);
|
||||
}
|
||||
}
|
||||
|
||||
describe("CounterService", () => {
|
||||
let service: CounterService;
|
||||
describe('CounterService', () => {
|
||||
let service: CounterService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(CounterService);
|
||||
});
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(CounterService);
|
||||
});
|
||||
|
||||
it("should increment count", () => {
|
||||
expect(service.count()).toBe(0);
|
||||
service.increment();
|
||||
expect(service.count()).toBe(1);
|
||||
});
|
||||
it('should increment count', () => {
|
||||
expect(service.count()).toBe(0);
|
||||
service.increment();
|
||||
expect(service.count()).toBe(1);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Service with HTTP
|
||||
|
||||
```typescript
|
||||
import {
|
||||
HttpTestingController,
|
||||
provideHttpClientTesting,
|
||||
} from "@angular/common/http/testing";
|
||||
import { provideHttpClient } from "@angular/common/http";
|
||||
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
|
||||
describe("UserService", () => {
|
||||
let service: UserService;
|
||||
let httpMock: HttpTestingController;
|
||||
describe('UserService', () => {
|
||||
let service: UserService;
|
||||
let httpMock: HttpTestingController;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [provideHttpClient(), provideHttpClientTesting()],
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [provideHttpClient(), provideHttpClientTesting()],
|
||||
});
|
||||
|
||||
service = TestBed.inject(UserService);
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
service = TestBed.inject(UserService);
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
httpMock.verify(); // Verify no outstanding requests
|
||||
});
|
||||
|
||||
it("should fetch user by id", () => {
|
||||
const mockUser = { id: "1", name: "Test User" };
|
||||
|
||||
service.getUser("1").subscribe((user) => {
|
||||
expect(user).toEqual(mockUser);
|
||||
afterEach(() => {
|
||||
httpMock.verify(); // Verify no outstanding requests
|
||||
});
|
||||
|
||||
const req = httpMock.expectOne("/api/users/1");
|
||||
expect(req.request.method).toBe("GET");
|
||||
req.flush(mockUser);
|
||||
});
|
||||
it('should fetch user by id', () => {
|
||||
const mockUser = { id: '1', name: 'Test User' };
|
||||
|
||||
service.getUser('1').subscribe((user) => {
|
||||
expect(user).toEqual(mockUser);
|
||||
});
|
||||
|
||||
const req = httpMock.expectOne('/api/users/1');
|
||||
expect(req.request.method).toBe('GET');
|
||||
req.flush(mockUser);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -281,31 +278,31 @@ describe("UserService", () => {
|
||||
### Using Vitest Mocks
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
describe("UserProfile", () => {
|
||||
const mockUserService = {
|
||||
getUser: vi.fn(),
|
||||
updateUser: vi.fn(),
|
||||
user: signal<User | null>(null),
|
||||
};
|
||||
describe('UserProfile', () => {
|
||||
const mockUserService = {
|
||||
getUser: vi.fn(),
|
||||
updateUser: vi.fn(),
|
||||
user: signal<User | null>(null),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
mockUserService.getUser.mockReturnValue(of({ id: "1", name: "Test" }));
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
mockUserService.getUser.mockReturnValue(of({ id: '1', name: 'Test' }));
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UserProfile],
|
||||
providers: [{ provide: UserService, useValue: mockUserService }],
|
||||
}).compileComponents();
|
||||
});
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UserProfile],
|
||||
providers: [{ provide: UserService, useValue: mockUserService }],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it("should call getUser on init", () => {
|
||||
const fixture = TestBed.createComponent(UserProfile);
|
||||
fixture.detectChanges();
|
||||
it('should call getUser on init', () => {
|
||||
const fixture = TestBed.createComponent(UserProfile);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(mockUserService.getUser).toHaveBeenCalledWith("1");
|
||||
});
|
||||
expect(mockUserService.getUser).toHaveBeenCalledWith('1');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -313,28 +310,26 @@ describe("UserProfile", () => {
|
||||
|
||||
```typescript
|
||||
const mockAuth = {
|
||||
user: signal<User | null>(null),
|
||||
isAuthenticated: computed(() => mockAuth.user() !== null),
|
||||
login: vi.fn(),
|
||||
logout: vi.fn(),
|
||||
user: signal<User | null>(null),
|
||||
isAuthenticated: computed(() => mockAuth.user() !== null),
|
||||
login: vi.fn(),
|
||||
logout: vi.fn(),
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ProtectedPage],
|
||||
providers: [{ provide: AuthService, useValue: mockAuth }],
|
||||
}).compileComponents();
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [ProtectedPage],
|
||||
providers: [{ provide: AuthService, useValue: mockAuth }],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it("should show content when authenticated", () => {
|
||||
mockAuth.user.set({ id: "1", name: "Test User" });
|
||||
it('should show content when authenticated', () => {
|
||||
mockAuth.user.set({ id: '1', name: 'Test User' });
|
||||
|
||||
const fixture = TestBed.createComponent(ProtectedPage);
|
||||
fixture.detectChanges();
|
||||
const fixture = TestBed.createComponent(ProtectedPage);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(
|
||||
fixture.nativeElement.querySelector(".protected-content"),
|
||||
).toBeTruthy();
|
||||
expect(fixture.nativeElement.querySelector('.protected-content')).toBeTruthy();
|
||||
});
|
||||
```
|
||||
|
||||
@@ -342,33 +337,33 @@ it("should show content when authenticated", () => {
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
selector: "app-item",
|
||||
template: `<div (click)="select()">{{ item().name }}</div>`,
|
||||
selector: 'app-item',
|
||||
template: `<div (click)="select()">{{ item().name }}</div>`,
|
||||
})
|
||||
export class ItemCmpt {
|
||||
item = input.required<Item>();
|
||||
selected = output<Item>();
|
||||
item = input.required<Item>();
|
||||
selected = output<Item>();
|
||||
|
||||
select() {
|
||||
this.selected.emit(this.item());
|
||||
}
|
||||
select() {
|
||||
this.selected.emit(this.item());
|
||||
}
|
||||
}
|
||||
|
||||
describe("ItemCmpt", () => {
|
||||
it("should emit selected event on click", () => {
|
||||
const fixture = TestBed.createComponent(ItemCmpt);
|
||||
const item: Item = { id: "1", name: "Test Item" };
|
||||
describe('ItemCmpt', () => {
|
||||
it('should emit selected event on click', () => {
|
||||
const fixture = TestBed.createComponent(ItemCmpt);
|
||||
const item: Item = { id: '1', name: 'Test Item' };
|
||||
|
||||
fixture.componentRef.setInput("item", item);
|
||||
fixture.detectChanges();
|
||||
fixture.componentRef.setInput('item', item);
|
||||
fixture.detectChanges();
|
||||
|
||||
let emittedItem: Item | undefined;
|
||||
fixture.componentInstance.selected.subscribe((i) => (emittedItem = i));
|
||||
let emittedItem: Item | undefined;
|
||||
fixture.componentInstance.selected.subscribe((i) => (emittedItem = i));
|
||||
|
||||
fixture.nativeElement.querySelector("div").click();
|
||||
fixture.nativeElement.querySelector('div').click();
|
||||
|
||||
expect(emittedItem).toEqual(item);
|
||||
});
|
||||
expect(emittedItem).toEqual(item);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
@@ -377,36 +372,36 @@ describe("ItemCmpt", () => {
|
||||
### Using fakeAsync
|
||||
|
||||
```typescript
|
||||
import { fakeAsync, tick, flush } from "@angular/core/testing";
|
||||
import { fakeAsync, tick, flush } from '@angular/core/testing';
|
||||
|
||||
it("should debounce search", fakeAsync(() => {
|
||||
const fixture = TestBed.createComponent(SearchCmpt);
|
||||
fixture.detectChanges();
|
||||
it('should debounce search', fakeAsync(() => {
|
||||
const fixture = TestBed.createComponent(SearchCmpt);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.query.set("test");
|
||||
fixture.componentInstance.query.set('test');
|
||||
|
||||
tick(300); // Advance time for debounce
|
||||
fixture.detectChanges();
|
||||
tick(300); // Advance time for debounce
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.results().length).toBeGreaterThan(0);
|
||||
expect(fixture.componentInstance.results().length).toBeGreaterThan(0);
|
||||
|
||||
flush(); // Flush remaining timers
|
||||
flush(); // Flush remaining timers
|
||||
}));
|
||||
```
|
||||
|
||||
### Using waitForAsync
|
||||
|
||||
```typescript
|
||||
import { waitForAsync } from "@angular/core/testing";
|
||||
import { waitForAsync } from '@angular/core/testing';
|
||||
|
||||
it("should load data", waitForAsync(() => {
|
||||
const fixture = TestBed.createComponent(DataCmpt);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
it('should load data', waitForAsync(() => {
|
||||
const fixture = TestBed.createComponent(DataCmpt);
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.data()).toBeDefined();
|
||||
});
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.data()).toBeDefined();
|
||||
});
|
||||
}));
|
||||
```
|
||||
|
||||
@@ -414,43 +409,43 @@ it("should load data", waitForAsync(() => {
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
template: `
|
||||
@if (userResource.isLoading()) {
|
||||
<p>Loading...</p>
|
||||
} @else if (userResource.hasValue()) {
|
||||
<p>{{ userResource.value().name }}</p>
|
||||
}
|
||||
`,
|
||||
template: `
|
||||
@if (userResource.isLoading()) {
|
||||
<p>Loading...</p>
|
||||
} @else if (userResource.hasValue()) {
|
||||
<p>{{ userResource.value().name }}</p>
|
||||
}
|
||||
`,
|
||||
})
|
||||
export class UserCmpt {
|
||||
userId = signal("1");
|
||||
userResource = httpResource<User>(() => `/api/users/${this.userId()}`);
|
||||
userId = signal('1');
|
||||
userResource = httpResource<User>(() => `/api/users/${this.userId()}`);
|
||||
}
|
||||
|
||||
describe("UserCmpt", () => {
|
||||
let httpMock: HttpTestingController;
|
||||
describe('UserCmpt', () => {
|
||||
let httpMock: HttpTestingController;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UserCmpt],
|
||||
providers: [provideHttpClient(), provideHttpClientTesting()],
|
||||
}).compileComponents();
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UserCmpt],
|
||||
providers: [provideHttpClient(), provideHttpClientTesting()],
|
||||
}).compileComponents();
|
||||
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
});
|
||||
httpMock = TestBed.inject(HttpTestingController);
|
||||
});
|
||||
|
||||
it("should display user name after loading", () => {
|
||||
const fixture = TestBed.createComponent(UserCmpt);
|
||||
fixture.detectChanges();
|
||||
it('should display user name after loading', () => {
|
||||
const fixture = TestBed.createComponent(UserCmpt);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.textContent).toContain("Loading");
|
||||
expect(fixture.nativeElement.textContent).toContain('Loading');
|
||||
|
||||
const req = httpMock.expectOne("/api/users/1");
|
||||
req.flush({ id: "1", name: "John Doe" });
|
||||
fixture.detectChanges();
|
||||
const req = httpMock.expectOne('/api/users/1');
|
||||
req.flush({ id: '1', name: 'John Doe' });
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.nativeElement.textContent).toContain("John Doe");
|
||||
});
|
||||
expect(fixture.nativeElement.textContent).toContain('John Doe');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user