@cdx-di-template/webtemplate-investment-widget 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,169 @@
1
+ import '@testing-library/jest-dom';
2
+ import React from 'react';
3
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
4
+ import { ThemeProvider } from '@mui/material';
5
+ import { createTheme } from '@mui/material/styles';
6
+ import <%= upperCamel(name) %> from './<%= upperCamel(name) %>';
7
+ import { environment } from '../environments/environment';
8
+ import investment from '../__mocks__/investmentMock.json';
9
+ import { PlatformSDK } from '@cdx-extensions/di-sdk';
10
+
11
+ jest.mock('@cdx-extensions/di-sdk', () => {
12
+ const mockGet = jest.fn();
13
+ const mockUseUserContext = jest.fn();
14
+ const mockUseBranding = jest.fn();
15
+ const instance = {
16
+ getHttpClient: () => ({
17
+ get: mockGet,
18
+ }),
19
+ useUserContext: mockUseUserContext,
20
+ useBranding: mockUseBranding,
21
+ };
22
+ return {
23
+ PlatformSDK: {
24
+ getInstance: jest.fn(() => instance),
25
+ },
26
+ };
27
+ });
28
+
29
+ const getSdkInstance = () => (PlatformSDK.getInstance as jest.Mock)();
30
+
31
+ const getMockGet = () => getSdkInstance().getHttpClient().get as jest.Mock;
32
+
33
+ const expectedBaseUrl =
34
+ environment.apiUrl || 'https://investmentmock.tiiny.site/investmentMock.json';
35
+
36
+ function renderWithHostTheme(ui: React.ReactElement) {
37
+ return render(
38
+ <ThemeProvider theme={createTheme()}>{ui}</ThemeProvider>,
39
+ );
40
+ }
41
+
42
+ describe('<<%= upperCamel(name) %> />', () => {
43
+ beforeEach(() => {
44
+ jest.clearAllMocks();
45
+ getMockGet().mockResolvedValue({ data: investment });
46
+ getSdkInstance().useUserContext.mockReturnValue({
47
+ data: { fullName: 'Test User', userName: 'testuser' },
48
+ });
49
+ getSdkInstance().useBranding.mockReturnValue({ theme: {} });
50
+ });
51
+
52
+ it('should render portfolio allocation and overview', () => {
53
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
54
+
55
+ expect(screen.getByText('Portfolio Allocation')).toBeInTheDocument();
56
+ expect(screen.getByText('Portfolio Overview')).toBeInTheDocument();
57
+ });
58
+
59
+ it('should render total value from mock portfolio data', () => {
60
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
61
+
62
+ expect(screen.getByText(/\$175,430\.50/)).toBeInTheDocument();
63
+ });
64
+
65
+ it('should render Refresh button', () => {
66
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
67
+
68
+ expect(screen.getByRole('button', { name: /Refresh/i })).toBeInTheDocument();
69
+ });
70
+
71
+ it('should render legend with holding symbols from mock data', () => {
72
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
73
+
74
+ expect(screen.getByText('AAPL')).toBeInTheDocument();
75
+ expect(screen.getByText('MSFT')).toBeInTheDocument();
76
+ });
77
+
78
+ it('should render Name label and fullName from user context under Portfolio Overview', () => {
79
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
80
+
81
+ expect(screen.getByText('Portfolio Overview')).toBeInTheDocument();
82
+ expect(screen.getByText(/Name\s*:/)).toBeInTheDocument();
83
+ expect(screen.getByText(/Test User/)).toBeInTheDocument();
84
+ });
85
+
86
+ it('should show N/A for Name when user context is undefined', () => {
87
+ getSdkInstance().useUserContext.mockReturnValue({ data: undefined });
88
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
89
+
90
+ expect(screen.getByText(/Name\s*:/)).toBeInTheDocument();
91
+ expect(screen.getByText(/N\/A/)).toBeInTheDocument();
92
+ });
93
+
94
+ it('should call get with base URL when Refresh button is clicked', async () => {
95
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
96
+
97
+ fireEvent.click(screen.getByRole('button', { name: /Refresh/i }));
98
+
99
+ await waitFor(() => {
100
+ expect(getMockGet()).toHaveBeenCalledWith(expectedBaseUrl);
101
+ });
102
+ });
103
+
104
+ it('should update portfolio data when Refresh succeeds', async () => {
105
+ const newTotal = 200000;
106
+ getMockGet().mockResolvedValue({
107
+ data: { ...investment, totalValue: newTotal },
108
+ });
109
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
110
+
111
+ fireEvent.click(screen.getByRole('button', { name: /Refresh/i }));
112
+
113
+ await waitFor(() => {
114
+ expect(screen.getByText(/\$200,000\.00/)).toBeInTheDocument();
115
+ });
116
+ });
117
+
118
+ it('should call alert and keep initial data when Refresh fails', async () => {
119
+ const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
120
+ getMockGet().mockRejectedValue(new Error('Network error'));
121
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
122
+
123
+ fireEvent.click(screen.getByRole('button', { name: /Refresh/i }));
124
+
125
+ await waitFor(() => {
126
+ expect(alertSpy).toHaveBeenCalledWith(new Error('Network error'));
127
+ });
128
+
129
+ expect(screen.getByText(/\$175,430\.50/)).toBeInTheDocument();
130
+ alertSpy.mockRestore();
131
+ });
132
+
133
+ it('should render donut center Total label and formatted total value', () => {
134
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
135
+
136
+ expect(screen.getByText('Total')).toBeInTheDocument();
137
+ expect(screen.getByText(/\$175,430\.50/)).toBeInTheDocument();
138
+ });
139
+
140
+ it('should render legend allocation percentages from mock data', () => {
141
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
142
+
143
+ expect(screen.getByText('6.3%')).toBeInTheDocument();
144
+ expect(screen.getByText('35.5%')).toBeInTheDocument();
145
+ });
146
+
147
+ it('should render all holding symbols from mock data in legend', () => {
148
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
149
+
150
+ const symbols = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA', 'SPY', 'VTI', 'BND'];
151
+ symbols.forEach(symbol => {
152
+ expect(screen.getByText(symbol)).toBeInTheDocument();
153
+ });
154
+ });
155
+
156
+ it('should call useUserContext and useBranding on mount (embedded)', () => {
157
+ renderWithHostTheme(<<%= upperCamel(name) %> />);
158
+
159
+ expect(getSdkInstance().useUserContext).toHaveBeenCalled();
160
+ expect(getSdkInstance().useBranding).toHaveBeenCalledWith('branding-1');
161
+ });
162
+
163
+ it('should render with standalone prop and call useBranding with branding-1', () => {
164
+ render(<<%= upperCamel(name) %> standalone />);
165
+
166
+ expect(screen.getByText('Portfolio Allocation')).toBeInTheDocument();
167
+ expect(getSdkInstance().useBranding).toHaveBeenCalledWith('branding-1');
168
+ });
169
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdx-di-template/webtemplate-investment-widget",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "license": "MIT",
5
5
  "description": "CDX web widget generator template files (investment-widget variant)",
6
6
  "publishConfig": {