@oanda/labs-widget-common 1.0.201 → 1.0.203

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,181 @@
1
+ "use strict";
2
+
3
+ var _react = require("@testing-library/react");
4
+ var _react2 = _interopRequireDefault(require("react"));
5
+ var _constants = require("../../constants");
6
+ var _types = require("../../types");
7
+ var _LayoutContext = require("./LayoutContext");
8
+ var _LayoutProvider = require("./LayoutProvider");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ let mockResizeCallback = () => {};
11
+ const mockUseResizeObserver = jest.fn(_ref => {
12
+ let {
13
+ onResize
14
+ } = _ref;
15
+ mockResizeCallback = onResize;
16
+ });
17
+ const mockUseDebounceCallback = jest.fn(callback => callback);
18
+ jest.mock('usehooks-ts', () => ({
19
+ useResizeObserver: props => mockUseResizeObserver(props),
20
+ useDebounceCallback: (callback, _delay, _options) => mockUseDebounceCallback(callback)
21
+ }));
22
+ const TestConsumerComponent = () => {
23
+ const context = _react2.default.useContext(_LayoutContext.LayoutContext);
24
+ if (!context) return null;
25
+ return _react2.default.createElement("div", null, _react2.default.createElement("span", {
26
+ "data-testid": "size"
27
+ }, context.size), _react2.default.createElement("span", {
28
+ "data-testid": "isDark"
29
+ }, context.isDark.toString()), _react2.default.createElement("span", {
30
+ "data-testid": "theme"
31
+ }, context.theme));
32
+ };
33
+ const renderLayoutProvider = props => {
34
+ return (0, _react.render)(_react2.default.createElement(_LayoutProvider.LayoutProvider, props, _react2.default.createElement(TestConsumerComponent, null)));
35
+ };
36
+ describe('LayoutProvider', () => {
37
+ beforeEach(() => {
38
+ jest.clearAllMocks();
39
+ mockResizeCallback = () => {};
40
+ });
41
+ it('renders children and provides default context values', () => {
42
+ renderLayoutProvider();
43
+ expect(_react.screen.getByTestId('layout-provider')).toBeInTheDocument();
44
+ expect(_react.screen.getByTestId('size')).toHaveTextContent('');
45
+ expect(_react.screen.getByTestId('isDark')).toHaveTextContent('false');
46
+ expect(_react.screen.getByTestId('theme')).toHaveTextContent(_types.Theme.Light);
47
+ expect(_react.screen.getByTestId('layout-provider')).toHaveClass('lw-p-[0.125rem]');
48
+ expect(_react.screen.getByTestId('layout-provider')).not.toHaveClass('lw-w-fit');
49
+ expect(_react.screen.getByTestId('layout-provider')).toHaveStyle('colorScheme: light');
50
+ });
51
+ it('provides dark theme context values when theme is Dark', () => {
52
+ renderLayoutProvider({
53
+ theme: _types.Theme.Dark
54
+ });
55
+ expect(_react.screen.getByTestId('isDark')).toHaveTextContent('true');
56
+ expect(_react.screen.getByTestId('theme')).toHaveTextContent(_types.Theme.Dark);
57
+ expect(_react.screen.getByTestId('layout-provider')).toHaveStyle('colorScheme: dark');
58
+ });
59
+ it('provides fixedSize when specified and does not listen to resize', () => {
60
+ renderLayoutProvider({
61
+ size: _types.Size.TABLET
62
+ });
63
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.TABLET);
64
+ (0, _react.act)(() => {
65
+ mockResizeCallback({
66
+ width: _constants.MOBILE_MAX_WIDTH - 100
67
+ });
68
+ });
69
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.TABLET);
70
+ expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);
71
+ });
72
+ it('applies lw-w-fit class when shouldFitContent is true', () => {
73
+ renderLayoutProvider({
74
+ shouldFitContent: true
75
+ });
76
+ expect(_react.screen.getByTestId('layout-provider')).toHaveClass('lw-w-fit');
77
+ });
78
+ it('removes padding when shouldRemovePadding is true and size is set', () => {
79
+ renderLayoutProvider({
80
+ shouldRemovePadding: true
81
+ });
82
+ (0, _react.act)(() => {
83
+ mockResizeCallback({
84
+ width: _constants.MOBILE_MAX_WIDTH
85
+ });
86
+ });
87
+ expect(_react.screen.getByTestId('layout-provider')).not.toHaveClass('lw-p-[0.125rem]');
88
+ });
89
+ it('does not apply padding if size is null, even if shouldRemovePadding is false', () => {
90
+ renderLayoutProvider({
91
+ shouldRemovePadding: false
92
+ });
93
+ expect(_react.screen.getByTestId('layout-provider')).not.toHaveClass('lw-p-[0.125rem]');
94
+ });
95
+ it('applies padding when size is set and shouldRemovePadding is false', () => {
96
+ renderLayoutProvider({
97
+ shouldRemovePadding: false
98
+ });
99
+ (0, _react.act)(() => {
100
+ mockResizeCallback({
101
+ width: _constants.MOBILE_MAX_WIDTH
102
+ });
103
+ });
104
+ expect(_react.screen.getByTestId('layout-provider')).toHaveClass('lw-p-[0.125rem]');
105
+ });
106
+ describe('onResize behavior', () => {
107
+ it('sets size to MOBILE when width is less than or equal to MOBILE_MAX_WIDTH', () => {
108
+ renderLayoutProvider();
109
+ (0, _react.act)(() => {
110
+ mockResizeCallback({
111
+ width: _constants.MOBILE_MAX_WIDTH
112
+ });
113
+ });
114
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.MOBILE);
115
+ (0, _react.act)(() => {
116
+ mockResizeCallback({
117
+ width: _constants.MOBILE_MAX_WIDTH - 100
118
+ });
119
+ });
120
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.MOBILE);
121
+ });
122
+ it('sets size to TABLET when width is between MOBILE_MAX_WIDTH and DESKTOP_MIN_WIDTH', () => {
123
+ renderLayoutProvider();
124
+ (0, _react.act)(() => {
125
+ mockResizeCallback({
126
+ width: _constants.MOBILE_MAX_WIDTH + 1
127
+ });
128
+ });
129
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.TABLET);
130
+ (0, _react.act)(() => {
131
+ mockResizeCallback({
132
+ width: _constants.DESKTOP_MIN_WIDTH - 1
133
+ });
134
+ });
135
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.TABLET);
136
+ });
137
+ it('sets size to DESKTOP when width is greater than or equal to DESKTOP_MIN_WIDTH', () => {
138
+ renderLayoutProvider();
139
+ (0, _react.act)(() => {
140
+ mockResizeCallback({
141
+ width: _constants.DESKTOP_MIN_WIDTH
142
+ });
143
+ });
144
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.DESKTOP);
145
+ (0, _react.act)(() => {
146
+ mockResizeCallback({
147
+ width: _constants.DESKTOP_MIN_WIDTH + 100
148
+ });
149
+ });
150
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.DESKTOP);
151
+ });
152
+ it('does not update size on resize if fixedSize is provided', () => {
153
+ renderLayoutProvider({
154
+ size: _types.Size.DESKTOP
155
+ });
156
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.DESKTOP);
157
+ (0, _react.act)(() => {
158
+ mockResizeCallback({
159
+ width: _constants.MOBILE_MAX_WIDTH - 100
160
+ });
161
+ });
162
+ expect(_react.screen.getByTestId('size')).toHaveTextContent(_types.Size.DESKTOP);
163
+ });
164
+ });
165
+ it('uses debounced callback for onResize', () => {
166
+ renderLayoutProvider();
167
+ expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);
168
+ expect(mockUseDebounceCallback).toHaveBeenCalledWith(expect.any(Function), 50, {
169
+ leading: true
170
+ });
171
+ });
172
+ it('calls useResizeObserver with ref and onResize', () => {
173
+ renderLayoutProvider();
174
+ expect(mockUseResizeObserver).toHaveBeenCalledTimes(1);
175
+ expect(mockUseResizeObserver).toHaveBeenCalledWith({
176
+ ref: expect.any(Object),
177
+ onResize: expect.any(Function)
178
+ });
179
+ });
180
+ });
181
+ //# sourceMappingURL=LayoutProvider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LayoutProvider.test.js","names":["_react","require","_react2","_interopRequireDefault","_constants","_types","_LayoutContext","_LayoutProvider","e","__esModule","default","mockResizeCallback","mockUseResizeObserver","jest","fn","_ref","onResize","mockUseDebounceCallback","callback","mock","useResizeObserver","props","useDebounceCallback","_delay","_options","TestConsumerComponent","context","React","useContext","LayoutContext","createElement","size","isDark","toString","theme","renderLayoutProvider","render","LayoutProvider","describe","beforeEach","clearAllMocks","it","expect","screen","getByTestId","toBeInTheDocument","toHaveTextContent","Theme","Light","toHaveClass","not","toHaveStyle","Dark","Size","TABLET","act","width","MOBILE_MAX_WIDTH","toHaveBeenCalledTimes","shouldFitContent","shouldRemovePadding","MOBILE","DESKTOP_MIN_WIDTH","DESKTOP","toHaveBeenCalledWith","any","Function","leading","ref","Object"],"sources":["../../../../src/providers/Layout/LayoutProvider.test.tsx"],"sourcesContent":["import { act, render, screen } from '@testing-library/react';\nimport React from 'react';\n\nimport { DESKTOP_MIN_WIDTH, MOBILE_MAX_WIDTH } from '../../constants';\nimport { Size, Theme } from '../../types';\nimport { LayoutContext } from './LayoutContext';\nimport type { LayoutWrapperProps } from './LayoutProvider';\nimport { LayoutProvider } from './LayoutProvider';\n\n// Mock usehooks-ts\nlet mockResizeCallback: (entry: { width: number }) => void = () => {};\nconst mockUseResizeObserver = jest.fn(({ onResize }) => {\n mockResizeCallback = onResize;\n});\nconst mockUseDebounceCallback = jest.fn((callback) => callback);\n\njest.mock('usehooks-ts', () => ({\n useResizeObserver: (props: any) => mockUseResizeObserver(props),\n useDebounceCallback: (callback: any, _delay: any, _options: any) =>\n mockUseDebounceCallback(callback),\n}));\n\nconst TestConsumerComponent = () => {\n const context = React.useContext(LayoutContext);\n if (!context) return null;\n return (\n <div>\n <span data-testid=\"size\">{context.size}</span>\n <span data-testid=\"isDark\">{context.isDark.toString()}</span>\n <span data-testid=\"theme\">{context.theme}</span>\n </div>\n );\n};\n\nconst renderLayoutProvider = (props?: Partial<LayoutWrapperProps>) => {\n return render(\n <LayoutProvider {...props}>\n <TestConsumerComponent />\n </LayoutProvider>\n );\n};\n\ndescribe('LayoutProvider', () => {\n beforeEach(() => {\n jest.clearAllMocks();\n // Reset mockResizeCallback to a no-op function before each test\n mockResizeCallback = () => {};\n });\n\n it('renders children and provides default context values', () => {\n renderLayoutProvider();\n expect(screen.getByTestId('layout-provider')).toBeInTheDocument();\n expect(screen.getByTestId('size')).toHaveTextContent(''); // Initially null\n expect(screen.getByTestId('isDark')).toHaveTextContent('false');\n expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Light);\n expect(screen.getByTestId('layout-provider')).toHaveClass(\n 'lw-p-[0.125rem]'\n ); // Padding by default when size is set\n expect(screen.getByTestId('layout-provider')).not.toHaveClass('lw-w-fit');\n expect(screen.getByTestId('layout-provider')).toHaveStyle(\n 'colorScheme: light'\n );\n });\n\n it('provides dark theme context values when theme is Dark', () => {\n renderLayoutProvider({ theme: Theme.Dark });\n expect(screen.getByTestId('isDark')).toHaveTextContent('true');\n expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Dark);\n expect(screen.getByTestId('layout-provider')).toHaveStyle(\n 'colorScheme: dark'\n );\n });\n\n it('provides fixedSize when specified and does not listen to resize', () => {\n renderLayoutProvider({ size: Size.TABLET });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n\n // Simulate resize\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });\n });\n // Size should remain fixed\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1); // onResize is debounced\n });\n\n it('applies lw-w-fit class when shouldFitContent is true', () => {\n renderLayoutProvider({ shouldFitContent: true });\n expect(screen.getByTestId('layout-provider')).toHaveClass('lw-w-fit');\n });\n\n it('removes padding when shouldRemovePadding is true and size is set', () => {\n renderLayoutProvider({ shouldRemovePadding: true });\n // Simulate resize to set a size, which would normally add padding\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH });\n });\n expect(screen.getByTestId('layout-provider')).not.toHaveClass(\n 'lw-p-[0.125rem]'\n );\n });\n\n it('does not apply padding if size is null, even if shouldRemovePadding is false', () => {\n renderLayoutProvider({ shouldRemovePadding: false });\n // Size is initially null, so no padding class should be applied yet\n expect(screen.getByTestId('layout-provider')).not.toHaveClass(\n 'lw-p-[0.125rem]'\n );\n });\n\n it('applies padding when size is set and shouldRemovePadding is false', () => {\n renderLayoutProvider({ shouldRemovePadding: false });\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH }); // This will set size to MOBILE\n });\n expect(screen.getByTestId('layout-provider')).toHaveClass(\n 'lw-p-[0.125rem]'\n );\n });\n\n describe('onResize behavior', () => {\n it('sets size to MOBILE when width is less than or equal to MOBILE_MAX_WIDTH', () => {\n renderLayoutProvider();\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);\n\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);\n });\n\n it('sets size to TABLET when width is between MOBILE_MAX_WIDTH and DESKTOP_MIN_WIDTH', () => {\n renderLayoutProvider();\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH + 1 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n\n act(() => {\n mockResizeCallback({ width: DESKTOP_MIN_WIDTH - 1 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n });\n\n it('sets size to DESKTOP when width is greater than or equal to DESKTOP_MIN_WIDTH', () => {\n renderLayoutProvider();\n act(() => {\n mockResizeCallback({ width: DESKTOP_MIN_WIDTH });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n\n act(() => {\n mockResizeCallback({ width: DESKTOP_MIN_WIDTH + 100 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n });\n\n it('does not update size on resize if fixedSize is provided', () => {\n renderLayoutProvider({ size: Size.DESKTOP });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });\n });\n // Size should remain fixed\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n });\n });\n\n it('uses debounced callback for onResize', () => {\n renderLayoutProvider();\n expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);\n expect(mockUseDebounceCallback).toHaveBeenCalledWith(\n expect.any(Function),\n 50,\n { leading: true }\n );\n });\n\n it('calls useResizeObserver with ref and onResize', () => {\n renderLayoutProvider();\n expect(mockUseResizeObserver).toHaveBeenCalledTimes(1);\n expect(mockUseResizeObserver).toHaveBeenCalledWith({\n ref: expect.any(Object), // React.RefObject\n onResize: expect.any(Function), // The debounced callback\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,178 @@
1
+ import { act, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import { DESKTOP_MIN_WIDTH, MOBILE_MAX_WIDTH } from '../../constants';
4
+ import { Size, Theme } from '../../types';
5
+ import { LayoutContext } from './LayoutContext';
6
+ import { LayoutProvider } from './LayoutProvider';
7
+ let mockResizeCallback = () => {};
8
+ const mockUseResizeObserver = jest.fn(_ref => {
9
+ let {
10
+ onResize
11
+ } = _ref;
12
+ mockResizeCallback = onResize;
13
+ });
14
+ const mockUseDebounceCallback = jest.fn(callback => callback);
15
+ jest.mock('usehooks-ts', () => ({
16
+ useResizeObserver: props => mockUseResizeObserver(props),
17
+ useDebounceCallback: (callback, _delay, _options) => mockUseDebounceCallback(callback)
18
+ }));
19
+ const TestConsumerComponent = () => {
20
+ const context = React.useContext(LayoutContext);
21
+ if (!context) return null;
22
+ return React.createElement("div", null, React.createElement("span", {
23
+ "data-testid": "size"
24
+ }, context.size), React.createElement("span", {
25
+ "data-testid": "isDark"
26
+ }, context.isDark.toString()), React.createElement("span", {
27
+ "data-testid": "theme"
28
+ }, context.theme));
29
+ };
30
+ const renderLayoutProvider = props => {
31
+ return render(React.createElement(LayoutProvider, props, React.createElement(TestConsumerComponent, null)));
32
+ };
33
+ describe('LayoutProvider', () => {
34
+ beforeEach(() => {
35
+ jest.clearAllMocks();
36
+ mockResizeCallback = () => {};
37
+ });
38
+ it('renders children and provides default context values', () => {
39
+ renderLayoutProvider();
40
+ expect(screen.getByTestId('layout-provider')).toBeInTheDocument();
41
+ expect(screen.getByTestId('size')).toHaveTextContent('');
42
+ expect(screen.getByTestId('isDark')).toHaveTextContent('false');
43
+ expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Light);
44
+ expect(screen.getByTestId('layout-provider')).toHaveClass('lw-p-[0.125rem]');
45
+ expect(screen.getByTestId('layout-provider')).not.toHaveClass('lw-w-fit');
46
+ expect(screen.getByTestId('layout-provider')).toHaveStyle('colorScheme: light');
47
+ });
48
+ it('provides dark theme context values when theme is Dark', () => {
49
+ renderLayoutProvider({
50
+ theme: Theme.Dark
51
+ });
52
+ expect(screen.getByTestId('isDark')).toHaveTextContent('true');
53
+ expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Dark);
54
+ expect(screen.getByTestId('layout-provider')).toHaveStyle('colorScheme: dark');
55
+ });
56
+ it('provides fixedSize when specified and does not listen to resize', () => {
57
+ renderLayoutProvider({
58
+ size: Size.TABLET
59
+ });
60
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
61
+ act(() => {
62
+ mockResizeCallback({
63
+ width: MOBILE_MAX_WIDTH - 100
64
+ });
65
+ });
66
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
67
+ expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);
68
+ });
69
+ it('applies lw-w-fit class when shouldFitContent is true', () => {
70
+ renderLayoutProvider({
71
+ shouldFitContent: true
72
+ });
73
+ expect(screen.getByTestId('layout-provider')).toHaveClass('lw-w-fit');
74
+ });
75
+ it('removes padding when shouldRemovePadding is true and size is set', () => {
76
+ renderLayoutProvider({
77
+ shouldRemovePadding: true
78
+ });
79
+ act(() => {
80
+ mockResizeCallback({
81
+ width: MOBILE_MAX_WIDTH
82
+ });
83
+ });
84
+ expect(screen.getByTestId('layout-provider')).not.toHaveClass('lw-p-[0.125rem]');
85
+ });
86
+ it('does not apply padding if size is null, even if shouldRemovePadding is false', () => {
87
+ renderLayoutProvider({
88
+ shouldRemovePadding: false
89
+ });
90
+ expect(screen.getByTestId('layout-provider')).not.toHaveClass('lw-p-[0.125rem]');
91
+ });
92
+ it('applies padding when size is set and shouldRemovePadding is false', () => {
93
+ renderLayoutProvider({
94
+ shouldRemovePadding: false
95
+ });
96
+ act(() => {
97
+ mockResizeCallback({
98
+ width: MOBILE_MAX_WIDTH
99
+ });
100
+ });
101
+ expect(screen.getByTestId('layout-provider')).toHaveClass('lw-p-[0.125rem]');
102
+ });
103
+ describe('onResize behavior', () => {
104
+ it('sets size to MOBILE when width is less than or equal to MOBILE_MAX_WIDTH', () => {
105
+ renderLayoutProvider();
106
+ act(() => {
107
+ mockResizeCallback({
108
+ width: MOBILE_MAX_WIDTH
109
+ });
110
+ });
111
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);
112
+ act(() => {
113
+ mockResizeCallback({
114
+ width: MOBILE_MAX_WIDTH - 100
115
+ });
116
+ });
117
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);
118
+ });
119
+ it('sets size to TABLET when width is between MOBILE_MAX_WIDTH and DESKTOP_MIN_WIDTH', () => {
120
+ renderLayoutProvider();
121
+ act(() => {
122
+ mockResizeCallback({
123
+ width: MOBILE_MAX_WIDTH + 1
124
+ });
125
+ });
126
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
127
+ act(() => {
128
+ mockResizeCallback({
129
+ width: DESKTOP_MIN_WIDTH - 1
130
+ });
131
+ });
132
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
133
+ });
134
+ it('sets size to DESKTOP when width is greater than or equal to DESKTOP_MIN_WIDTH', () => {
135
+ renderLayoutProvider();
136
+ act(() => {
137
+ mockResizeCallback({
138
+ width: DESKTOP_MIN_WIDTH
139
+ });
140
+ });
141
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
142
+ act(() => {
143
+ mockResizeCallback({
144
+ width: DESKTOP_MIN_WIDTH + 100
145
+ });
146
+ });
147
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
148
+ });
149
+ it('does not update size on resize if fixedSize is provided', () => {
150
+ renderLayoutProvider({
151
+ size: Size.DESKTOP
152
+ });
153
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
154
+ act(() => {
155
+ mockResizeCallback({
156
+ width: MOBILE_MAX_WIDTH - 100
157
+ });
158
+ });
159
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
160
+ });
161
+ });
162
+ it('uses debounced callback for onResize', () => {
163
+ renderLayoutProvider();
164
+ expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);
165
+ expect(mockUseDebounceCallback).toHaveBeenCalledWith(expect.any(Function), 50, {
166
+ leading: true
167
+ });
168
+ });
169
+ it('calls useResizeObserver with ref and onResize', () => {
170
+ renderLayoutProvider();
171
+ expect(mockUseResizeObserver).toHaveBeenCalledTimes(1);
172
+ expect(mockUseResizeObserver).toHaveBeenCalledWith({
173
+ ref: expect.any(Object),
174
+ onResize: expect.any(Function)
175
+ });
176
+ });
177
+ });
178
+ //# sourceMappingURL=LayoutProvider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LayoutProvider.test.js","names":["act","render","screen","React","DESKTOP_MIN_WIDTH","MOBILE_MAX_WIDTH","Size","Theme","LayoutContext","LayoutProvider","mockResizeCallback","mockUseResizeObserver","jest","fn","_ref","onResize","mockUseDebounceCallback","callback","mock","useResizeObserver","props","useDebounceCallback","_delay","_options","TestConsumerComponent","context","useContext","createElement","size","isDark","toString","theme","renderLayoutProvider","describe","beforeEach","clearAllMocks","it","expect","getByTestId","toBeInTheDocument","toHaveTextContent","Light","toHaveClass","not","toHaveStyle","Dark","TABLET","width","toHaveBeenCalledTimes","shouldFitContent","shouldRemovePadding","MOBILE","DESKTOP","toHaveBeenCalledWith","any","Function","leading","ref","Object"],"sources":["../../../../src/providers/Layout/LayoutProvider.test.tsx"],"sourcesContent":["import { act, render, screen } from '@testing-library/react';\nimport React from 'react';\n\nimport { DESKTOP_MIN_WIDTH, MOBILE_MAX_WIDTH } from '../../constants';\nimport { Size, Theme } from '../../types';\nimport { LayoutContext } from './LayoutContext';\nimport type { LayoutWrapperProps } from './LayoutProvider';\nimport { LayoutProvider } from './LayoutProvider';\n\n// Mock usehooks-ts\nlet mockResizeCallback: (entry: { width: number }) => void = () => {};\nconst mockUseResizeObserver = jest.fn(({ onResize }) => {\n mockResizeCallback = onResize;\n});\nconst mockUseDebounceCallback = jest.fn((callback) => callback);\n\njest.mock('usehooks-ts', () => ({\n useResizeObserver: (props: any) => mockUseResizeObserver(props),\n useDebounceCallback: (callback: any, _delay: any, _options: any) =>\n mockUseDebounceCallback(callback),\n}));\n\nconst TestConsumerComponent = () => {\n const context = React.useContext(LayoutContext);\n if (!context) return null;\n return (\n <div>\n <span data-testid=\"size\">{context.size}</span>\n <span data-testid=\"isDark\">{context.isDark.toString()}</span>\n <span data-testid=\"theme\">{context.theme}</span>\n </div>\n );\n};\n\nconst renderLayoutProvider = (props?: Partial<LayoutWrapperProps>) => {\n return render(\n <LayoutProvider {...props}>\n <TestConsumerComponent />\n </LayoutProvider>\n );\n};\n\ndescribe('LayoutProvider', () => {\n beforeEach(() => {\n jest.clearAllMocks();\n // Reset mockResizeCallback to a no-op function before each test\n mockResizeCallback = () => {};\n });\n\n it('renders children and provides default context values', () => {\n renderLayoutProvider();\n expect(screen.getByTestId('layout-provider')).toBeInTheDocument();\n expect(screen.getByTestId('size')).toHaveTextContent(''); // Initially null\n expect(screen.getByTestId('isDark')).toHaveTextContent('false');\n expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Light);\n expect(screen.getByTestId('layout-provider')).toHaveClass(\n 'lw-p-[0.125rem]'\n ); // Padding by default when size is set\n expect(screen.getByTestId('layout-provider')).not.toHaveClass('lw-w-fit');\n expect(screen.getByTestId('layout-provider')).toHaveStyle(\n 'colorScheme: light'\n );\n });\n\n it('provides dark theme context values when theme is Dark', () => {\n renderLayoutProvider({ theme: Theme.Dark });\n expect(screen.getByTestId('isDark')).toHaveTextContent('true');\n expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Dark);\n expect(screen.getByTestId('layout-provider')).toHaveStyle(\n 'colorScheme: dark'\n );\n });\n\n it('provides fixedSize when specified and does not listen to resize', () => {\n renderLayoutProvider({ size: Size.TABLET });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n\n // Simulate resize\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });\n });\n // Size should remain fixed\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1); // onResize is debounced\n });\n\n it('applies lw-w-fit class when shouldFitContent is true', () => {\n renderLayoutProvider({ shouldFitContent: true });\n expect(screen.getByTestId('layout-provider')).toHaveClass('lw-w-fit');\n });\n\n it('removes padding when shouldRemovePadding is true and size is set', () => {\n renderLayoutProvider({ shouldRemovePadding: true });\n // Simulate resize to set a size, which would normally add padding\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH });\n });\n expect(screen.getByTestId('layout-provider')).not.toHaveClass(\n 'lw-p-[0.125rem]'\n );\n });\n\n it('does not apply padding if size is null, even if shouldRemovePadding is false', () => {\n renderLayoutProvider({ shouldRemovePadding: false });\n // Size is initially null, so no padding class should be applied yet\n expect(screen.getByTestId('layout-provider')).not.toHaveClass(\n 'lw-p-[0.125rem]'\n );\n });\n\n it('applies padding when size is set and shouldRemovePadding is false', () => {\n renderLayoutProvider({ shouldRemovePadding: false });\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH }); // This will set size to MOBILE\n });\n expect(screen.getByTestId('layout-provider')).toHaveClass(\n 'lw-p-[0.125rem]'\n );\n });\n\n describe('onResize behavior', () => {\n it('sets size to MOBILE when width is less than or equal to MOBILE_MAX_WIDTH', () => {\n renderLayoutProvider();\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);\n\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);\n });\n\n it('sets size to TABLET when width is between MOBILE_MAX_WIDTH and DESKTOP_MIN_WIDTH', () => {\n renderLayoutProvider();\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH + 1 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n\n act(() => {\n mockResizeCallback({ width: DESKTOP_MIN_WIDTH - 1 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);\n });\n\n it('sets size to DESKTOP when width is greater than or equal to DESKTOP_MIN_WIDTH', () => {\n renderLayoutProvider();\n act(() => {\n mockResizeCallback({ width: DESKTOP_MIN_WIDTH });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n\n act(() => {\n mockResizeCallback({ width: DESKTOP_MIN_WIDTH + 100 });\n });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n });\n\n it('does not update size on resize if fixedSize is provided', () => {\n renderLayoutProvider({ size: Size.DESKTOP });\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n\n act(() => {\n mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });\n });\n // Size should remain fixed\n expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);\n });\n });\n\n it('uses debounced callback for onResize', () => {\n renderLayoutProvider();\n expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);\n expect(mockUseDebounceCallback).toHaveBeenCalledWith(\n expect.any(Function),\n 50,\n { leading: true }\n );\n });\n\n it('calls useResizeObserver with ref and onResize', () => {\n renderLayoutProvider();\n expect(mockUseResizeObserver).toHaveBeenCalledTimes(1);\n expect(mockUseResizeObserver).toHaveBeenCalledWith({\n ref: expect.any(Object), // React.RefObject\n onResize: expect.any(Function), // The debounced callback\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oanda/labs-widget-common",
3
- "version": "1.0.201",
3
+ "version": "1.0.203",
4
4
  "description": "Labs Widget Common",
5
5
  "main": "dist/main/index.js",
6
6
  "module": "dist/module/index.js",
@@ -21,5 +21,5 @@
21
21
  "tailwind-merge": "2.2.2",
22
22
  "usehooks-ts": "3.0.2"
23
23
  },
24
- "gitHead": "d169d28768e8ae81eebf622af3bccc945538f8bf"
24
+ "gitHead": "b686126bf921097400e16b67184865f22f46c520"
25
25
  }
@@ -0,0 +1,191 @@
1
+ import { act, render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+
4
+ import { DESKTOP_MIN_WIDTH, MOBILE_MAX_WIDTH } from '../../constants';
5
+ import { Size, Theme } from '../../types';
6
+ import { LayoutContext } from './LayoutContext';
7
+ import type { LayoutWrapperProps } from './LayoutProvider';
8
+ import { LayoutProvider } from './LayoutProvider';
9
+
10
+ // Mock usehooks-ts
11
+ let mockResizeCallback: (entry: { width: number }) => void = () => {};
12
+ const mockUseResizeObserver = jest.fn(({ onResize }) => {
13
+ mockResizeCallback = onResize;
14
+ });
15
+ const mockUseDebounceCallback = jest.fn((callback) => callback);
16
+
17
+ jest.mock('usehooks-ts', () => ({
18
+ useResizeObserver: (props: any) => mockUseResizeObserver(props),
19
+ useDebounceCallback: (callback: any, _delay: any, _options: any) =>
20
+ mockUseDebounceCallback(callback),
21
+ }));
22
+
23
+ const TestConsumerComponent = () => {
24
+ const context = React.useContext(LayoutContext);
25
+ if (!context) return null;
26
+ return (
27
+ <div>
28
+ <span data-testid="size">{context.size}</span>
29
+ <span data-testid="isDark">{context.isDark.toString()}</span>
30
+ <span data-testid="theme">{context.theme}</span>
31
+ </div>
32
+ );
33
+ };
34
+
35
+ const renderLayoutProvider = (props?: Partial<LayoutWrapperProps>) => {
36
+ return render(
37
+ <LayoutProvider {...props}>
38
+ <TestConsumerComponent />
39
+ </LayoutProvider>
40
+ );
41
+ };
42
+
43
+ describe('LayoutProvider', () => {
44
+ beforeEach(() => {
45
+ jest.clearAllMocks();
46
+ // Reset mockResizeCallback to a no-op function before each test
47
+ mockResizeCallback = () => {};
48
+ });
49
+
50
+ it('renders children and provides default context values', () => {
51
+ renderLayoutProvider();
52
+ expect(screen.getByTestId('layout-provider')).toBeInTheDocument();
53
+ expect(screen.getByTestId('size')).toHaveTextContent(''); // Initially null
54
+ expect(screen.getByTestId('isDark')).toHaveTextContent('false');
55
+ expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Light);
56
+ expect(screen.getByTestId('layout-provider')).toHaveClass(
57
+ 'lw-p-[0.125rem]'
58
+ ); // Padding by default when size is set
59
+ expect(screen.getByTestId('layout-provider')).not.toHaveClass('lw-w-fit');
60
+ expect(screen.getByTestId('layout-provider')).toHaveStyle(
61
+ 'colorScheme: light'
62
+ );
63
+ });
64
+
65
+ it('provides dark theme context values when theme is Dark', () => {
66
+ renderLayoutProvider({ theme: Theme.Dark });
67
+ expect(screen.getByTestId('isDark')).toHaveTextContent('true');
68
+ expect(screen.getByTestId('theme')).toHaveTextContent(Theme.Dark);
69
+ expect(screen.getByTestId('layout-provider')).toHaveStyle(
70
+ 'colorScheme: dark'
71
+ );
72
+ });
73
+
74
+ it('provides fixedSize when specified and does not listen to resize', () => {
75
+ renderLayoutProvider({ size: Size.TABLET });
76
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
77
+
78
+ // Simulate resize
79
+ act(() => {
80
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });
81
+ });
82
+ // Size should remain fixed
83
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
84
+ expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1); // onResize is debounced
85
+ });
86
+
87
+ it('applies lw-w-fit class when shouldFitContent is true', () => {
88
+ renderLayoutProvider({ shouldFitContent: true });
89
+ expect(screen.getByTestId('layout-provider')).toHaveClass('lw-w-fit');
90
+ });
91
+
92
+ it('removes padding when shouldRemovePadding is true and size is set', () => {
93
+ renderLayoutProvider({ shouldRemovePadding: true });
94
+ // Simulate resize to set a size, which would normally add padding
95
+ act(() => {
96
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH });
97
+ });
98
+ expect(screen.getByTestId('layout-provider')).not.toHaveClass(
99
+ 'lw-p-[0.125rem]'
100
+ );
101
+ });
102
+
103
+ it('does not apply padding if size is null, even if shouldRemovePadding is false', () => {
104
+ renderLayoutProvider({ shouldRemovePadding: false });
105
+ // Size is initially null, so no padding class should be applied yet
106
+ expect(screen.getByTestId('layout-provider')).not.toHaveClass(
107
+ 'lw-p-[0.125rem]'
108
+ );
109
+ });
110
+
111
+ it('applies padding when size is set and shouldRemovePadding is false', () => {
112
+ renderLayoutProvider({ shouldRemovePadding: false });
113
+ act(() => {
114
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH }); // This will set size to MOBILE
115
+ });
116
+ expect(screen.getByTestId('layout-provider')).toHaveClass(
117
+ 'lw-p-[0.125rem]'
118
+ );
119
+ });
120
+
121
+ describe('onResize behavior', () => {
122
+ it('sets size to MOBILE when width is less than or equal to MOBILE_MAX_WIDTH', () => {
123
+ renderLayoutProvider();
124
+ act(() => {
125
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH });
126
+ });
127
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);
128
+
129
+ act(() => {
130
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });
131
+ });
132
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.MOBILE);
133
+ });
134
+
135
+ it('sets size to TABLET when width is between MOBILE_MAX_WIDTH and DESKTOP_MIN_WIDTH', () => {
136
+ renderLayoutProvider();
137
+ act(() => {
138
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH + 1 });
139
+ });
140
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
141
+
142
+ act(() => {
143
+ mockResizeCallback({ width: DESKTOP_MIN_WIDTH - 1 });
144
+ });
145
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.TABLET);
146
+ });
147
+
148
+ it('sets size to DESKTOP when width is greater than or equal to DESKTOP_MIN_WIDTH', () => {
149
+ renderLayoutProvider();
150
+ act(() => {
151
+ mockResizeCallback({ width: DESKTOP_MIN_WIDTH });
152
+ });
153
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
154
+
155
+ act(() => {
156
+ mockResizeCallback({ width: DESKTOP_MIN_WIDTH + 100 });
157
+ });
158
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
159
+ });
160
+
161
+ it('does not update size on resize if fixedSize is provided', () => {
162
+ renderLayoutProvider({ size: Size.DESKTOP });
163
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
164
+
165
+ act(() => {
166
+ mockResizeCallback({ width: MOBILE_MAX_WIDTH - 100 });
167
+ });
168
+ // Size should remain fixed
169
+ expect(screen.getByTestId('size')).toHaveTextContent(Size.DESKTOP);
170
+ });
171
+ });
172
+
173
+ it('uses debounced callback for onResize', () => {
174
+ renderLayoutProvider();
175
+ expect(mockUseDebounceCallback).toHaveBeenCalledTimes(1);
176
+ expect(mockUseDebounceCallback).toHaveBeenCalledWith(
177
+ expect.any(Function),
178
+ 50,
179
+ { leading: true }
180
+ );
181
+ });
182
+
183
+ it('calls useResizeObserver with ref and onResize', () => {
184
+ renderLayoutProvider();
185
+ expect(mockUseResizeObserver).toHaveBeenCalledTimes(1);
186
+ expect(mockUseResizeObserver).toHaveBeenCalledWith({
187
+ ref: expect.any(Object), // React.RefObject
188
+ onResize: expect.any(Function), // The debounced callback
189
+ });
190
+ });
191
+ });