Skip to content

Commit 8c471a1

Browse files
fix(devtools): do not throw if devtools are unavailable
1 parent 174eb09 commit 8c471a1

File tree

3 files changed

+106
-91
lines changed

3 files changed

+106
-91
lines changed

apps/demo/e2e/devtools.spec.ts

Lines changed: 101 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,112 @@
11
import { test, expect } from '@playwright/test';
22
import { Action } from '@ngrx/store';
33

4-
test('has title', async ({ page }) => {
5-
await page.goto('');
4+
test.describe('DevTools', () => {
5+
test('DevTools do not throw an error when not available', async ({
6+
page,
7+
}) => {
8+
await page.goto('');
9+
const errors = [];
10+
page.on('pageerror', (error) => errors.push(error));
11+
await page.getByRole('link', { name: 'DevTools' }).click();
12+
await expect(
13+
page.getByRole('row', { name: 'Go for a walk' })
14+
).toBeVisible();
15+
});
616

7-
await page.evaluate(() => {
8-
window['devtoolsSpy'] = [];
17+
test('DevTools are syncing state changes', async ({ page }) => {
18+
await page.goto('');
919

10-
window['__REDUX_DEVTOOLS_EXTENSION__'] = {
11-
connect: () => {
12-
return {
13-
send: (data: Action) => {
14-
window['devtoolsSpy'].push(data);
15-
},
16-
};
17-
},
18-
};
19-
});
20-
await page.getByRole('link', { name: 'DevTools' }).click();
21-
await page
22-
.getByRole('row', { name: 'Go for a walk' })
23-
.getByRole('checkbox')
24-
.click();
25-
await page
26-
.getByRole('row', { name: 'Exercise' })
27-
.getByRole('checkbox')
28-
.click();
20+
await page.evaluate(() => {
21+
window['devtoolsSpy'] = [];
2922

30-
await expect(
31-
page.getByRole('region', { name: 'Go for a walk' })
32-
).toBeVisible();
33-
await expect(page.getByRole('region', { name: 'Exercise' })).toBeVisible();
23+
window['__REDUX_DEVTOOLS_EXTENSION__'] = {
24+
connect: () => {
25+
return {
26+
send: (data: Action) => {
27+
window['devtoolsSpy'].push(data);
28+
},
29+
};
30+
},
31+
};
32+
});
33+
await page.getByRole('link', { name: 'DevTools' }).click();
34+
await page
35+
.getByRole('row', { name: 'Go for a walk' })
36+
.getByRole('checkbox')
37+
.click();
38+
await page
39+
.getByRole('row', { name: 'Exercise' })
40+
.getByRole('checkbox')
41+
.click();
3442

35-
await page
36-
.getByRole('row', { name: 'Go for a walk' })
37-
.getByRole('checkbox')
38-
.click();
39-
await page
40-
.getByRole('row', { name: 'Exercise' })
41-
.getByRole('checkbox')
42-
.click();
43+
await expect(
44+
page.getByRole('region', { name: 'Go for a walk' })
45+
).toBeVisible();
46+
await expect(page.getByRole('region', { name: 'Exercise' })).toBeVisible();
4347

44-
await expect(
45-
page.getByRole('region', { name: 'Go for a walk' })
46-
).toBeHidden();
47-
await expect(page.getByRole('region', { name: 'Exercise' })).toBeHidden();
48+
await page
49+
.getByRole('row', { name: 'Go for a walk' })
50+
.getByRole('checkbox')
51+
.click();
52+
await page
53+
.getByRole('row', { name: 'Exercise' })
54+
.getByRole('checkbox')
55+
.click();
4856

49-
const devtoolsActions = await page.evaluate(() => window['devtoolsSpy']);
57+
await expect(
58+
page.getByRole('region', { name: 'Go for a walk' })
59+
).toBeHidden();
60+
await expect(page.getByRole('region', { name: 'Exercise' })).toBeHidden();
5061

51-
expect(devtoolsActions).toEqual([
52-
{
53-
type: 'add todo',
54-
},
55-
{
56-
type: 'select todo 1',
57-
},
58-
{
59-
type: 'Store Update',
60-
},
61-
{
62-
type: 'Store Update',
63-
},
64-
{
65-
type: 'Store Update',
66-
},
67-
{
68-
type: 'select todo 4',
69-
},
70-
{
71-
type: 'Store Update',
72-
},
73-
{
74-
type: 'Store Update',
75-
},
76-
{
77-
type: 'Store Update',
78-
},
79-
{
80-
type: 'select todo 1',
81-
},
82-
{
83-
type: 'Store Update',
84-
},
85-
{
86-
type: 'Store Update',
87-
},
88-
{
89-
type: 'select todo 4',
90-
},
91-
{
92-
type: 'Store Update',
93-
},
94-
{
95-
type: 'Store Update',
96-
},
97-
]);
62+
const devtoolsActions = await page.evaluate(() => window['devtoolsSpy']);
63+
64+
expect(devtoolsActions).toEqual([
65+
{
66+
type: 'add todo',
67+
},
68+
{
69+
type: 'select todo 1',
70+
},
71+
{
72+
type: 'Store Update',
73+
},
74+
{
75+
type: 'Store Update',
76+
},
77+
{
78+
type: 'Store Update',
79+
},
80+
{
81+
type: 'select todo 4',
82+
},
83+
{
84+
type: 'Store Update',
85+
},
86+
{
87+
type: 'Store Update',
88+
},
89+
{
90+
type: 'Store Update',
91+
},
92+
{
93+
type: 'select todo 1',
94+
},
95+
{
96+
type: 'Store Update',
97+
},
98+
{
99+
type: 'Store Update',
100+
},
101+
{
102+
type: 'select todo 4',
103+
},
104+
{
105+
type: 'Store Update',
106+
},
107+
{
108+
type: 'Store Update',
109+
},
110+
]);
111+
});
98112
});

libs/ngrx-toolkit/src/lib/devtools/internal/devtools-syncer.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export class DevtoolsSyncer implements OnDestroy {
6363

6464
const isToolkitAvailable = Boolean(window.__REDUX_DEVTOOLS_EXTENSION__);
6565
if (!isToolkitAvailable) {
66-
throw new Error(
66+
console.info(
6767
'NgRx Toolkit/DevTools: Redux DevTools Extension is not available.'
6868
);
6969
}

libs/ngrx-toolkit/src/lib/devtools/tests/connecting.spec.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ describe('connect & send', () => {
1616
expect(connectSpy).toHaveBeenCalledTimes(0);
1717
});
1818

19-
it('should not connect if it runs on the server', () => {
20-
const { connectSpy } = setupExtensions(false);
21-
expect(connectSpy).toHaveBeenCalledTimes(0);
19+
it('should not throw if it runs on the server', () => {
20+
setupExtensions(true, false);
21+
const Store = signalStore({ providedIn: 'root' }, withDevtools('flight'));
22+
expect(() => TestBed.inject(Store)).not.toThrowError();
2223
});
2324

2425
it('should only send when store is initialized', () => {

0 commit comments

Comments
 (0)