Skip to content

Commit 618dfc7

Browse files
committed
test: add lifecycle interaction tests
1 parent 927bc85 commit 618dfc7

File tree

1 file changed

+132
-4
lines changed

1 file changed

+132
-4
lines changed

projects/angular-redux/src/tests/inject-selector.spec.ts

Lines changed: 132 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import {InjectSelector, injectSelector, provideRedux} from '../public-api'
2-
import {Component} from "@angular/core";
3-
import {render} from "@testing-library/angular";
1+
import {InjectSelector, injectSelector, provideRedux, ReduxProvider} from '../public-api'
2+
import {Component, effect, inject} from "@angular/core";
3+
import {render, waitFor} from "@testing-library/angular";
44
import {AnyAction, createStore, Store} from "redux";
55
import '@testing-library/jest-dom';
6+
import {Subscription} from "../lib/utils/Subscription";
67

78
type NormalStateType = {
89
count: number
@@ -58,10 +59,137 @@ describe('injectSelector core subscription behavior', () => {
5859
expect(await findByText("Count: 0")).toBeInTheDocument();
5960
expect(selector).toHaveBeenCalledTimes(1)
6061

61-
normalStore.dispatch({ type: '' })
62+
normalStore.dispatch({type: ''})
6263

6364

6465
expect(await findByText("Count: 1")).toBeInTheDocument();
6566
expect(selector).toHaveBeenCalledTimes(2)
6667
})
6768
})
69+
70+
describe('injectSelector lifecycle interactions', () => {
71+
it('always uses the latest state', async () => {
72+
const store = createStore((c: number = 1): number => c + 1, -1)
73+
74+
@Component({
75+
selector: "app-root",
76+
standalone: true,
77+
template: "<div></div>"
78+
})
79+
class Testing {
80+
selector = (c: number): number => c + 1
81+
value = injectSelector(this.selector)
82+
_test = effect(() => {
83+
renderedItems.push(this.value())
84+
})
85+
}
86+
87+
await render(Testing, {
88+
providers: [provideRedux({store})]
89+
})
90+
91+
expect(renderedItems).toEqual([1])
92+
93+
store.dispatch({type: ''})
94+
95+
await waitFor(() =>
96+
expect(renderedItems).toEqual([1, 2])
97+
)
98+
})
99+
100+
it('subscribes to the store synchronously', async () => {
101+
let appSubscription: Subscription | null = null
102+
103+
@Component({
104+
selector: "child-root",
105+
standalone: true,
106+
template: "<div>{{count()}}</div>"
107+
})
108+
class Child {
109+
count = injectNormalSelector((s) => s.count)
110+
}
111+
112+
function injectReduxAndAssignApp() {
113+
const contextVal = inject(ReduxProvider);
114+
appSubscription = contextVal && contextVal.subscription
115+
return contextVal;
116+
}
117+
118+
@Component({
119+
selector: "app-root",
120+
standalone: true,
121+
imports: [Child],
122+
template: `
123+
@if (count() === 1) {
124+
<child-root/>
125+
}
126+
`
127+
})
128+
class Parent {
129+
contextVal = injectReduxAndAssignApp();
130+
count = injectNormalSelector((s) => s.count)
131+
}
132+
133+
await render(Parent, {
134+
providers: [provideRedux({store: normalStore})]
135+
})
136+
137+
// Parent component only
138+
expect(appSubscription!.getListeners().get().length).toBe(1)
139+
140+
normalStore.dispatch({type: ''})
141+
142+
// Parent component + 1 child component
143+
await waitFor(() =>
144+
expect(appSubscription!.getListeners().get().length).toBe(2)
145+
)
146+
})
147+
148+
it('unsubscribes when the component is unmounted', async () => {
149+
let appSubscription: Subscription | null = null
150+
151+
@Component({
152+
selector: "child-root",
153+
standalone: true,
154+
template: "<div>{{count()}}</div>"
155+
})
156+
class Child {
157+
count = injectNormalSelector((s) => s.count)
158+
}
159+
160+
function injectReduxAndAssignApp() {
161+
const contextVal = inject(ReduxProvider);
162+
appSubscription = contextVal && contextVal.subscription
163+
return contextVal;
164+
}
165+
166+
@Component({
167+
selector: "app-root",
168+
standalone: true,
169+
imports: [Child],
170+
template: `
171+
@if (count() === 0) {
172+
<child-root/>
173+
}
174+
`
175+
})
176+
class Parent {
177+
contextVal = injectReduxAndAssignApp();
178+
count = injectNormalSelector((s) => s.count)
179+
}
180+
181+
await render(Parent, {
182+
providers: [provideRedux({store: normalStore})]
183+
})
184+
185+
// Parent component only
186+
expect(appSubscription!.getListeners().get().length).toBe(2)
187+
188+
normalStore.dispatch({type: ''})
189+
190+
// Parent component + 1 child component
191+
await waitFor(() =>
192+
expect(appSubscription!.getListeners().get().length).toBe(1)
193+
)
194+
})
195+
});

0 commit comments

Comments
 (0)