英文:
How to detect store change in component after dispatch NgRx Unit testing
问题
在将状态从'light'更改为'dark'后,它不会在组件中更改。它会保持状态为'light',即使我已经分派了一个将其更改为'dark'的操作。有没有办法在组件中检测到它?
以下是单元测试文件
app.component.spec.ts
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let compiled: HTMLElement;
let store: MockStore;
const initialState = {
theme: fromTheme.initialState,
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [AppRoutingModule],
providers: [provideMockStore({ initialState })],
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
compiled = fixture.debugElement.nativeElement;
store = TestBed.get<MockStore>(MockStore);
});
it('should create the app', () => {
expect(component).toBeTruthy();
});
it('should have a class with theme', () => {
expect(compiled.classList.contains('light')).toBeTrue();
store.dispatch(fromTheme.changeTheme({ payload: 'dark' }));
fixture.detectChanges();
expect(compiled.classList.contains('dark')).toBeTrue();
});
});
以下是组件文件
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
host: {
'[class.light]': 'theme === "light"',
'[class.dark]': 'theme === "dark"',
},
})
export class AppComponent implements OnInit, OnDestroy {
theme: ThemeType = 'light';
themeSubscription: Subscription | null = null;
constructor(
private store: Store<AppStore>,
) {}
ngOnInit() {
this.themeSubscription = this.store.select(selectTheme).subscribe((themeState) => {
this.theme = themeState.theme;
if (!themeState.isChanged) {
const preferredTheme = getPreferredTheme();
this.store.dispatch(changeTheme({ payload: preferredTheme }));
}
});
}
ngOnDestroy() {
this.themeSubscription?.unsubscribe();
}
}
英文:
After changing the the state from 'light' to 'dark' it's not gonna change it in component. It will keep the state as 'light' even though I have dispatched an action which is gonna change it to dark.
Is there a way to detect it in component?
Here is the unit test file
app.component.spec.ts
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let compiled: HTMLElement;
let store: MockStore;
const initialState = {
theme: fromTheme.initialState,
};
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [AppRoutingModule],
providers: [provideMockStore({ initialState })],
}).compileComponents();
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
compiled = fixture.debugElement.nativeElement;
store = TestBed.get<MockStore>(MockStore);
});
it('should create the app', () => {
expect(component).toBeTruthy();
});
it('should have a class with theme', () => {
expect(compiled.classList.contains('light')).toBeTrue();
store.dispatch(fromTheme.changeTheme({ payload: 'dark' }));
fixture.detectChanges();
expect(compiled.classList.contains('dark')).toBeTrue();
});
});
Here is the component file
app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
host: {
'[class.light]': 'theme === "light"',
'[class.dark]': 'theme === "dark"',
},
})
export class AppComponent implements OnInit, OnDestroy {
theme: ThemeType = 'light';
themeSubscription: Subscription | null = null;
constructor(
private store: Store<AppStore>,
) {}
ngOnInit() {
this.themeSubscription = this.store.select(selectTheme).subscribe((themeState) => {
this.theme = themeState.theme;
if (!themeState.isChanged) {
const preferredTheme = getPreferredTheme();
this.store.dispatch(changeTheme({ payload: preferredTheme }));
}
});
}
ngOnDestroy() {
this.themeSubscription?.unsubscribe();
}
}
答案1
得分: 1
provideMockStore
不运行 reducers/effects。
因为 reducer 是一个纯函数,所以通过 reducer 方法进行测试更容易。这样做也可以加快测试速度,因为你不需要 TestBed/Setup/Component。
示例请参见 https://timdeschryver.dev/blog/testing-an-ngrx-project#reducers
如果你需要测试组件,那么你需要手动设置状态/覆盖选择器,参见 https://ngrx.io/guide/store/testing#using-mock-selectors 以获取示例。
或者,不使用 mockstore,依赖于真实的实现。
英文:
provideMockStore
doesn't run the reducers/effects.
Because a reducer is a pure function it's also easier to just test the reducer via the reducer method. This makes your tests also faster because you don't need the TestBed/Setup/Component.
For an example see https://timdeschryver.dev/blog/testing-an-ngrx-project#reducers
If you need to test the component then you need to set the state manually/override the selector, see https://ngrx.io/guide/store/testing#using-mock-selectors for an example.
Or, don't use the mockstore and rely on the real impementation.
答案2
得分: 0
以下是翻译好的代码部分:
不需要提供模拟存储,而可以像这样提供真实存储:
let store: Store<AppStore>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [AppRoutingModule, StoreModule.forRoot(appReducer)],
});
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
compiled = fixture.debugElement.nativeElement;
store = TestBed.get<Store>(Store);
});
然后组件将监听此存储中的更改,并且调度将起作用。
测试示例:
it('应该具有包含主题的类', () => {
store.select(fromTheme.selectTheme)
.subscribe((themeState) => {
expect(compiled.classList.contains(themeState.theme)).toBeTrue();
});
});
---
it('应该能够调度changeTheme', () => {
const newTheme = 'dark';
store.dispatch(fromTheme.changeTheme({ payload: newTheme }));
expect(compiled.classList.contains(newTheme)).toBeTrue();
});
请注意,上面的翻译是给出的代码部分的中文翻译,不包含其他内容。
英文:
There was no need to provide a mock store, instead of that, we can provide the real store like this
let store: Store<AppStore>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
imports: [AppRoutingModule, StoreModule.forRoot(appReducer)],
});
fixture = TestBed.createComponent(AppComponent);
component = fixture.componentInstance;
fixture.detectChanges();
compiled = fixture.debugElement.nativeElement;
store = TestBed.get<Store>(Store);
});
Then the component will listen for changes in this store, and the dispatch will work.
Test Examples:
it('should have a class with theme', () => {
store.select(fromTheme.selectTheme)
.subscribe((themeState) => {
expect(compiled.classList.contains(themeState.theme)).toBeTrue();
});
});
it('should be able to dispatch the changeTheme', () => {
const newTheme = 'dark';
store.dispatch(fromTheme.changeTheme({ payload: newTheme }));
expect(compiled.classList.contains(newTheme)).toBeTrue();
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论