@griddo/ax 12.4.0 → 12.5.1

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.
Files changed (37) hide show
  1. package/config/__tests__/ModulePathInMessagesPlugin.test.js +93 -0
  2. package/config/webpack/ModulePathInMessagesPlugin.js +47 -0
  3. package/config/webpack.config.js +10 -0
  4. package/package.json +2 -2
  5. package/src/__tests__/components/ConfigPanel/Form/Form.test.tsx +47 -57
  6. package/src/__tests__/components/ConfigPanel/Header/Header.test.tsx +46 -42
  7. package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +6 -17
  8. package/src/__tests__/components/EmptyState/EmptyState.test.tsx +9 -9
  9. package/src/__tests__/components/Fields/AsyncSelect/AsyncSelect.test.tsx +60 -50
  10. package/src/__tests__/components/Fields/ColorPicker/ColorPicker.test.tsx +66 -58
  11. package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +222 -425
  12. package/src/__tests__/components/Fields/FileField/FileField.test.tsx +13 -14
  13. package/src/__tests__/components/Fields/ImageField/ImageField.test.tsx +275 -259
  14. package/src/__tests__/components/Fields/IntegrationsField/IntegrationsField.test.tsx +50 -48
  15. package/src/__tests__/components/Fields/NoteField/NoteField.test.tsx +9 -8
  16. package/src/__tests__/components/Fields/NumberField/NumberField.test.tsx +8 -12
  17. package/src/__tests__/components/Fields/TextArea/TextArea.test.tsx +6 -2
  18. package/src/__tests__/components/Fields/ToggleField/ToggleField.test.tsx +15 -23
  19. package/src/__tests__/components/Fields/Tooltip/Tooltip.test.tsx +8 -2
  20. package/src/__tests__/components/Fields/VisualUniqueSelection/VisualUniqueSelection.test.tsx +29 -21
  21. package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.config.test.tsx +103 -0
  22. package/src/__tests__/components/FieldsBehavior/FieldsBehavior.test.tsx +7 -2
  23. package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +8 -6
  24. package/src/__tests__/components/SideModal/SideModal.test.tsx +150 -104
  25. package/src/__tests__/components/TableFilters/LiveFilter/LiveFilter.test.tsx +15 -29
  26. package/src/__tests__/components/TableFilters/StatusFilter/StatusFilter.test.tsx +61 -36
  27. package/src/__tests__/components/Tabs/Tabs.test.tsx +65 -61
  28. package/src/__tests__/components/Toast/Toast.test.tsx +19 -21
  29. package/src/__tests__/modules/FramePreview/FramePreview.test.tsx +16 -0
  30. package/src/__tests__/modules/Sites/SitesList/ListView/BulkHeader/BulkHeader.test.tsx +24 -19
  31. package/src/__tests__/modules/Sites/SitesList/SitesList.test.tsx +15 -6
  32. package/src/__tests__/modules/Users/Roles/BulkHeader/BulkHeader.test.tsx +69 -64
  33. package/src/__tests__/modules/Users/Roles/Roles.test.tsx +7 -4
  34. package/src/components/Fields/Wysiwyg/config.tsx +68 -17
  35. package/src/components/Fields/Wysiwyg/helpers.tsx +2 -0
  36. package/src/components/Fields/Wysiwyg/index.tsx +41 -10
  37. package/src/components/ResizePanel/index.tsx +7 -2
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Guards the fix for webpack 5 dropping the file name from module warnings.
3
+ *
4
+ * webpack 4 gave CRA warnings as strings carrying their own `./src/Foo.tsx` header;
5
+ * webpack 5 moves it to a `moduleName` field that `formatWebpackMessages` ignores,
6
+ * which left "Attempted import error: 'x' is not exported from './styles.module.css'"
7
+ * pointing at no file in particular.
8
+ */
9
+ const formatWebpackMessages = require("react-dev-utils/formatWebpackMessages");
10
+
11
+ const ModulePathInMessagesPlugin = require("../webpack/ModulePathInMessagesPlugin");
12
+
13
+ /** Minimal stand-in for the two tapable hooks the plugin uses. */
14
+ const runPlugin = ({ warnings = [], errors = [] } = {}) => {
15
+ const compilation = {
16
+ warnings,
17
+ errors,
18
+ requestShortener: {},
19
+ hooks: { afterSeal: { tap: (_name, fn) => fn() } },
20
+ };
21
+ const compiler = { hooks: { compilation: { tap: (_name, fn) => fn(compilation) } } };
22
+
23
+ new ModulePathInMessagesPlugin().apply(compiler);
24
+
25
+ return compilation;
26
+ };
27
+
28
+ const makeWarning = (message, { module = true, loc = { start: { line: 2, column: 12 } } } = {}) => ({
29
+ message,
30
+ loc,
31
+ module: module ? { readableIdentifier: () => "./src/ui/modules/Wysiwyg/index.tsx" } : undefined,
32
+ });
33
+
34
+ describe("ModulePathInMessagesPlugin", () => {
35
+ test("prefixes the warning with the module path and location", () => {
36
+ const warning = makeWarning("export 'intro' was not found in './styles.module.css'");
37
+
38
+ runPlugin({ warnings: [warning] });
39
+
40
+ expect(warning.message).toBe(
41
+ "./src/ui/modules/Wysiwyg/index.tsx:2:12\nexport 'intro' was not found in './styles.module.css'",
42
+ );
43
+ });
44
+
45
+ test("decorates errors too", () => {
46
+ const error = makeWarning("Module not found");
47
+
48
+ runPlugin({ errors: [error] });
49
+
50
+ expect(error.message).toBe("./src/ui/modules/Wysiwyg/index.tsx:2:12\nModule not found");
51
+ });
52
+
53
+ test("omits the location when the warning has none", () => {
54
+ const warning = makeWarning("boom", { loc: null });
55
+
56
+ runPlugin({ warnings: [warning] });
57
+
58
+ expect(warning.message).toBe("./src/ui/modules/Wysiwyg/index.tsx\nboom");
59
+ });
60
+
61
+ test("leaves warnings that are not attached to a module alone", () => {
62
+ const warning = makeWarning("something global", { module: false });
63
+
64
+ runPlugin({ warnings: [warning] });
65
+
66
+ expect(warning.message).toBe("something global");
67
+ });
68
+
69
+ test("does not prefix twice across watch-mode rebuilds", () => {
70
+ const warning = makeWarning("export 'intro' was not found in './styles.module.css'");
71
+
72
+ runPlugin({ warnings: [warning] });
73
+ const afterFirstBuild = warning.message;
74
+ runPlugin({ warnings: [warning] });
75
+
76
+ expect(warning.message).toBe(afterFirstBuild);
77
+ });
78
+
79
+ // The contract that makes the whole thing worthwhile: formatWebpackMessages
80
+ // rewrites the export line wholesale and strips a trailing `2:12-24` off line 0,
81
+ // so the header has to survive both to reach the terminal.
82
+ test("the path survives formatWebpackMessages", () => {
83
+ const warning = makeWarning("export 'intro' (imported as 'styles') was not found in './styles.module.css'");
84
+
85
+ runPlugin({ warnings: [warning] });
86
+ const [formatted] = formatWebpackMessages({ errors: [], warnings: [{ message: warning.message }] }).warnings;
87
+
88
+ expect(formatted).toBe(
89
+ "./src/ui/modules/Wysiwyg/index.tsx:2:12\n" +
90
+ "Attempted import error: 'intro' is not exported from './styles.module.css' (imported as 'styles').",
91
+ );
92
+ });
93
+ });
@@ -0,0 +1,47 @@
1
+ const NAME = "GriddoModulePathInMessages";
2
+
3
+ /**
4
+ * Prefixes every module-attached warning/error with the file that caused it.
5
+ *
6
+ * webpack 4 handed CRA its warnings as plain strings that already carried the
7
+ * `./src/Foo.tsx 2:12-24` header. webpack 5 hands them over as objects
8
+ * (`{ message, moduleName, loc }`), and `react-dev-utils`'s `formatWebpackMessages`
9
+ * only reads `.message` — so the file and location are dropped on the floor.
10
+ * That leaves messages like "Attempted import error: 'intro' is not exported
11
+ * from './styles.module.css'" with no way to tell which of the many
12
+ * `styles.module.css` files is at fault.
13
+ *
14
+ * Folding the location back into `.message` restores the webpack 4 shape that
15
+ * `formatWebpackMessages` expects (line 0 = file, line 1 = message), and it fixes
16
+ * both paths at once: `griddo build` (which calls the formatter directly) and
17
+ * `griddo start` (where `createCompiler` calls it internally, out of our reach).
18
+ */
19
+ class ModulePathInMessagesPlugin {
20
+ apply(compiler) {
21
+ compiler.hooks.compilation.tap(NAME, (compilation) => {
22
+ // `afterSeal` runs once dependency warnings have been collected and before
23
+ // anything can call `stats.toJson()`.
24
+ compilation.hooks.afterSeal.tap(NAME, () => {
25
+ const decorate = (err) => {
26
+ const module = err.module;
27
+ if (!module || typeof module.readableIdentifier !== "function") {
28
+ return;
29
+ }
30
+ const name = module.readableIdentifier(compilation.requestShortener);
31
+ const loc = err.loc?.start ? `:${err.loc.start.line}:${err.loc.start.column}` : "";
32
+ const header = `${name}${loc}`;
33
+ // Guard against double-prefixing on watch-mode rebuilds that reuse errors.
34
+ if (typeof err.message !== "string" || err.message.startsWith(header)) {
35
+ return;
36
+ }
37
+ err.message = `${header}\n${err.message}`;
38
+ };
39
+
40
+ compilation.warnings.forEach(decorate);
41
+ compilation.errors.forEach(decorate);
42
+ });
43
+ });
44
+ }
45
+ }
46
+
47
+ module.exports = ModulePathInMessagesPlugin;
@@ -18,6 +18,7 @@ const ModuleNotFoundPlugin = require("react-dev-utils/ModuleNotFoundPlugin");
18
18
  const ForkTsCheckerWebpackPlugin = require("react-dev-utils/ForkTsCheckerWebpackPlugin");
19
19
  const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
20
20
  const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
21
+ const ModulePathInMessagesPlugin = require("./webpack/ModulePathInMessagesPlugin");
21
22
  const createEnvironmentHash = require("./webpack/persistentCache/createEnvironmentHash");
22
23
 
23
24
  const postcssNormalize = require("postcss-normalize");
@@ -466,6 +467,9 @@ module.exports = function (webpackEnv) {
466
467
  importLoaders: 1,
467
468
  sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
468
469
  modules: {
470
+ // Both keys below are a contract with client projects, not an
471
+ // internal build detail: packages/griddo-ax/docs/adr/0001-contrato-de-css-modules-con-los-clientes.md
472
+ //
469
473
  // css-loader v6 defaults `esModule: true`, so `import * as styles`
470
474
  // only sees locals as named exports when `namedExport` is on.
471
475
  // griddo-components relies on `import * as styles` heavily.
@@ -509,6 +513,8 @@ module.exports = function (webpackEnv) {
509
513
  importLoaders: 3,
510
514
  sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
511
515
  modules: {
516
+ // Same client-facing contract as the CSS modules block above
517
+ // (ADR 0001): keep both keys in sync with it.
512
518
  namedExport: true,
513
519
  exportLocalsConvention: "asIs",
514
520
  getLocalIdent: getCSSModuleLocalIdent,
@@ -543,6 +549,10 @@ module.exports = function (webpackEnv) {
543
549
  ],
544
550
  },
545
551
  plugins: [
552
+ // webpack 5 moves the offending file out of the warning text and into a
553
+ // separate `moduleName` field that react-dev-utils' formatter ignores. This
554
+ // folds it back in so messages point at a file again.
555
+ new ModulePathInMessagesPlugin(),
546
556
  // Restore webpack 4's Node core-module handling for browser bundles. Clients run
547
557
  // `griddo build` (this config) against their own instance, so this guards legacy
548
558
  // instances against "Module not found" for Node builtins that webpack 5 no longer
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "12.4.0",
4
+ "version": "12.5.1",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Diego M. Béjar <diego.bejar@secuoyas.com>",
@@ -199,5 +199,5 @@
199
199
  "publishConfig": {
200
200
  "access": "public"
201
201
  },
202
- "gitHead": "e78fd612e55753bf9a04aa1e4020b582be9026af"
202
+ "gitHead": "0341f4c939ce5e316e37effdaca2ef26dee8b8af"
203
203
  }
@@ -1,4 +1,3 @@
1
- import type { MockedFunction } from "vitest";
2
1
  import * as React from "react";
3
2
 
4
3
  import { ThemeProvider } from "styled-components";
@@ -113,49 +112,49 @@ const initialStore = {
113
112
  };
114
113
  const store = mockStore(initialStore);
115
114
 
116
- const defaultProps = mock<IFormProps>();
117
-
118
- defaultProps.schema = {
119
- title: "Header",
120
- component: "Header",
121
- type: "header",
122
- configTabs: [
115
+ // Props por test. Los tres `const ...Mock = defaultProps.x as MockedFunction<>`
116
+ // que había aquí no se usaban en ningún assert: solo servían, sin querer, para
117
+ // materializar esas props en el proxy de `mock<T>()` y que el spread de JSX las
118
+ // llevara al componente. Ahora van declaradas en la factoría.
119
+ const makeProps = (overrides: Partial<IFormProps> = {}): IFormProps =>
120
+ Object.assign(
121
+ mock<IFormProps>(),
123
122
  {
124
- title: "content",
125
- fields: [
126
- {
127
- title: "Name",
128
- key: "title",
129
- type: "TextField",
130
- mandatory: true,
131
- },
132
- ],
123
+ schema: {
124
+ title: "Header",
125
+ component: "Header",
126
+ type: "header",
127
+ configTabs: [
128
+ {
129
+ title: "content",
130
+ fields: [
131
+ {
132
+ title: "Name",
133
+ key: "title",
134
+ type: "TextField",
135
+ mandatory: true,
136
+ },
137
+ ],
138
+ },
139
+ ],
140
+ schemaType: "module",
141
+ },
142
+ selectedTab: "content",
143
+ isPage: false,
144
+ isGlobal: false,
145
+ theme: "default-theme",
146
+ setSelectedContent: vi.fn(),
147
+ setSelectedTab: vi.fn(),
148
+ setHistoryPush: vi.fn(),
133
149
  },
134
- ],
135
- schemaType: "module",
136
- };
137
- const restorePageNavigationActionMock = vi.fn();
138
- defaultProps.actions = {
139
- restorePageNavigationAction: restorePageNavigationActionMock,
140
- };
141
- const setSelectedContentMock = defaultProps.setSelectedContent as MockedFunction<(editorID: number) => void>;
142
- const setSelectedTabMocked = defaultProps.setSelectedTab as MockedFunction<(tab: string) => void>;
143
- const setHistoryPushMocked = defaultProps.setHistoryPush as MockedFunction<
144
- (path: string, isEditor: boolean) => void
145
- >;
146
- defaultProps.selectedTab = "content";
147
- defaultProps.isPage = false;
148
- defaultProps.isGlobal = false;
149
- defaultProps.theme = "default-theme";
150
+ overrides,
151
+ );
150
152
 
151
153
  describe("Form component rendering", () => {
152
154
  it("should render the component", () => {
153
- defaultProps.isPage = true;
154
- defaultProps.isGlobal = true;
155
-
156
155
  render(
157
156
  <ThemeProvider theme={parseTheme(globalTheme)}>
158
- <Form {...defaultProps} />
157
+ <Form {...makeProps({ isPage: true, isGlobal: true })} />
159
158
  </ThemeProvider>,
160
159
  { store },
161
160
  );
@@ -163,13 +162,9 @@ describe("Form component rendering", () => {
163
162
  });
164
163
 
165
164
  it("should render the component with no header warning text", () => {
166
- defaultProps.isPage = false;
167
- defaultProps.isGlobal = false;
168
- defaultProps.header = 0;
169
-
170
165
  render(
171
166
  <ThemeProvider theme={parseTheme(globalTheme)}>
172
- <Form {...defaultProps} />
167
+ <Form {...makeProps({ header: 0 })} />
173
168
  </ThemeProvider>,
174
169
  { store },
175
170
  );
@@ -178,11 +173,11 @@ describe("Form component rendering", () => {
178
173
  });
179
174
 
180
175
  it("should call the function to restore the header", () => {
181
- defaultProps.header = 0;
176
+ const restorePageNavigationAction = vi.fn();
182
177
 
183
178
  render(
184
179
  <ThemeProvider theme={parseTheme(globalTheme)}>
185
- <Form {...defaultProps} />
180
+ <Form {...makeProps({ header: 0, actions: { restorePageNavigationAction } })} />
186
181
  </ThemeProvider>,
187
182
  { store },
188
183
  );
@@ -190,16 +185,14 @@ describe("Form component rendering", () => {
190
185
  expect(screen.getByText(/This page doesn\'t have a header. Click/i)).toBeInTheDocument();
191
186
  const headerLink = screen.getByTestId("header-link");
192
187
  fireEvent.click(headerLink);
193
- expect(restorePageNavigationActionMock).toBeCalled();
194
- expect(restorePageNavigationActionMock).toBeCalledWith("header");
188
+ expect(restorePageNavigationAction).toBeCalled();
189
+ expect(restorePageNavigationAction).toBeCalledWith("header");
195
190
  });
196
191
 
197
192
  it("should render the component with no footer warning text", () => {
198
- defaultProps.footer = 0;
199
-
200
193
  render(
201
194
  <ThemeProvider theme={parseTheme(globalTheme)}>
202
- <Form {...defaultProps} />
195
+ <Form {...makeProps({ header: 0, footer: 0 })} />
203
196
  </ThemeProvider>,
204
197
  { store },
205
198
  );
@@ -208,11 +201,11 @@ describe("Form component rendering", () => {
208
201
  });
209
202
 
210
203
  it("should call the function to restore the header", () => {
211
- defaultProps.header = 0;
204
+ const restorePageNavigationAction = vi.fn();
212
205
 
213
206
  render(
214
207
  <ThemeProvider theme={parseTheme(globalTheme)}>
215
- <Form {...defaultProps} />
208
+ <Form {...makeProps({ header: 0, footer: 0, actions: { restorePageNavigationAction } })} />
216
209
  </ThemeProvider>,
217
210
  { store },
218
211
  );
@@ -220,17 +213,14 @@ describe("Form component rendering", () => {
220
213
  expect(screen.getByText(/This page doesn\'t have a header. Click/i)).toBeInTheDocument();
221
214
  const footerLink = screen.getByTestId("footer-link");
222
215
  fireEvent.click(footerLink);
223
- expect(restorePageNavigationActionMock).toBeCalled();
224
- expect(restorePageNavigationActionMock).toBeCalledWith("footer");
216
+ expect(restorePageNavigationAction).toBeCalled();
217
+ expect(restorePageNavigationAction).toBeCalledWith("footer");
225
218
  });
226
219
 
227
220
  it("should render the tabs", () => {
228
- defaultProps.isPage = true;
229
- defaultProps.isGlobal = true;
230
-
231
221
  render(
232
222
  <ThemeProvider theme={parseTheme(globalTheme)}>
233
- <Form {...defaultProps} />
223
+ <Form {...makeProps({ isPage: true, isGlobal: true, header: 0, footer: 0 })} />
234
224
  </ThemeProvider>,
235
225
  { store },
236
226
  );
@@ -1,4 +1,3 @@
1
- import type { MockedFunction } from "vitest";
2
1
  import * as React from "react";
3
2
 
4
3
  import { ThemeProvider } from "styled-components";
@@ -73,52 +72,57 @@ const initialStore = {
73
72
 
74
73
  const store = mockStore(initialStore);
75
74
 
76
- const defaultProps = mock<IHeaderProps>();
77
- defaultProps.actions = {
78
- duplicateModuleAction: vi.fn(),
79
- deleteModuleAction: vi.fn(),
80
- copyModuleAction: vi.fn(),
81
- };
82
- const setSelectedContentMock = defaultProps.setSelectedContent as MockedFunction<(editorID: number) => void>;
83
-
84
- defaultProps.schema = {
85
- title: "Header",
86
- component: "Header",
87
- type: "header",
88
- configTabs: [
75
+ const makeProps = (overrides: Partial<IHeaderProps> = {}): IHeaderProps =>
76
+ Object.assign(
77
+ mock<IHeaderProps>(),
89
78
  {
90
- title: "content",
91
- fields: [
79
+ actions: {
80
+ duplicateModuleAction: vi.fn(),
81
+ deleteModuleAction: vi.fn(),
82
+ copyModuleAction: vi.fn(),
83
+ },
84
+ schema: {
85
+ title: "Header",
86
+ component: "Header",
87
+ type: "header",
88
+ configTabs: [
89
+ {
90
+ title: "content",
91
+ fields: [
92
+ {
93
+ title: "Name",
94
+ key: "title",
95
+ type: "TextField",
96
+ mandatory: true,
97
+ },
98
+ ],
99
+ },
100
+ ],
101
+ schemaType: "module",
102
+ },
103
+ breadcrumb: [
92
104
  {
93
- title: "Name",
94
- key: "title",
95
- type: "TextField",
96
- mandatory: true,
105
+ editorID: 0,
106
+ component: "TextField",
107
+ displayName: "Texto",
97
108
  },
98
109
  ],
110
+ activatedModules: ["TextField"],
111
+ headerRef: { current: { offsetHeight: 63, offsetTop: 24 } } as React.RefObject<HTMLDivElement>,
112
+ // El proxy de `mock<T>()` solo materializa una prop cuando se accede a
113
+ // ella, y el spread de JSX únicamente copia las propias: los callbacks
114
+ // que el componente invoca tienen que estar puestos aquí.
115
+ setSelectedContent: vi.fn(),
116
+ setHeaderHeight: vi.fn(),
99
117
  },
100
- ],
101
- schemaType: "module",
102
- };
103
-
104
- defaultProps.breadcrumb = [
105
- {
106
- editorID: 0,
107
- component: "TextField",
108
- displayName: "Texto",
109
- },
110
- ];
111
-
112
- defaultProps.activatedModules = ["TextField"];
113
-
114
- defaultProps.headerRef = { current: { offsetHeight: 63, offsetTop: 24 } } as React.RefObject<HTMLDivElement>;
115
- const setHeaderHeightMock = defaultProps.setHeaderHeight as MockedFunction<(height: number) => void>;
118
+ overrides,
119
+ );
116
120
 
117
121
  describe("Header component rendering", () => {
118
122
  it("should render component", () => {
119
123
  render(
120
124
  <ThemeProvider theme={parseTheme(globalTheme)}>
121
- <Header {...defaultProps} />
125
+ <Header {...makeProps()} />
122
126
  </ThemeProvider>,
123
127
  { store },
124
128
  );
@@ -129,11 +133,9 @@ describe("Header component rendering", () => {
129
133
  });
130
134
 
131
135
  it("should render the actions menu when clicking the more info button", () => {
132
- defaultProps.selectedParent = [];
133
-
134
136
  render(
135
137
  <ThemeProvider theme={parseTheme(globalTheme)}>
136
- <Header {...defaultProps} />
138
+ <Header {...makeProps({ selectedParent: [] })} />
137
139
  </ThemeProvider>,
138
140
  { store },
139
141
  );
@@ -145,9 +147,11 @@ describe("Header component rendering", () => {
145
147
  });
146
148
 
147
149
  it("should trigger the duplicate action", () => {
150
+ const setSelectedContent = vi.fn();
151
+
148
152
  render(
149
153
  <ThemeProvider theme={parseTheme(globalTheme)}>
150
- <Header {...defaultProps} />
154
+ <Header {...makeProps({ selectedParent: [], setSelectedContent })} />
151
155
  </ThemeProvider>,
152
156
  { store },
153
157
  );
@@ -157,6 +161,6 @@ describe("Header component rendering", () => {
157
161
  const listItem = screen.getAllByTestId("action-menu-item");
158
162
  expect(listItem).toHaveLength(3);
159
163
  fireEvent.click(listItem[0]);
160
- expect(setSelectedContentMock).toBeCalled();
164
+ expect(setSelectedContent).toBeCalled();
161
165
  });
162
166
  });
@@ -11,13 +11,14 @@ import globalTheme from "@ax/themes/theme.json";
11
11
 
12
12
  afterEach(cleanup);
13
13
 
14
- const defaultProps = mock<IElementsTooltipProps>();
14
+ const makeProps = (overrides: Partial<IElementsTooltipProps> = {}): IElementsTooltipProps =>
15
+ Object.assign(mock<IElementsTooltipProps>(), overrides);
15
16
 
16
17
  describe("Tooltip component rendering", () => {
17
18
  it("should not render the component", () => {
18
19
  render(
19
20
  <ThemeProvider theme={parseTheme(globalTheme)}>
20
- <ElementsTooltip {...defaultProps} />
21
+ <ElementsTooltip {...makeProps()} />
21
22
  </ThemeProvider>,
22
23
  );
23
24
 
@@ -27,13 +28,9 @@ describe("Tooltip component rendering", () => {
27
28
  });
28
29
 
29
30
  it("should render the component with one element visible", async () => {
30
- defaultProps.elements = ["uno", "dos", "tres"];
31
- defaultProps.colors = { uno: "#fff" };
32
- defaultProps.rounded = true;
33
-
34
31
  render(
35
32
  <ThemeProvider theme={parseTheme(globalTheme)}>
36
- <ElementsTooltip {...defaultProps} />
33
+ <ElementsTooltip {...makeProps({ elements: ["uno", "dos", "tres"], colors: { uno: "#fff" }, rounded: true })} />
37
34
  </ThemeProvider>,
38
35
  );
39
36
 
@@ -59,13 +56,9 @@ describe("Tooltip component rendering", () => {
59
56
  });
60
57
 
61
58
  it("should render the component with three elements visibles", () => {
62
- defaultProps.elements = ["uno", "dos", "tres"];
63
- defaultProps.defaultElements = 3;
64
- defaultProps.maxChar = 1;
65
-
66
59
  render(
67
60
  <ThemeProvider theme={parseTheme(globalTheme)}>
68
- <ElementsTooltip {...defaultProps} />
61
+ <ElementsTooltip {...makeProps({ elements: ["uno", "dos", "tres"], defaultElements: 3, maxChar: 1 })} />
69
62
  </ThemeProvider>,
70
63
  );
71
64
 
@@ -79,13 +72,9 @@ describe("Tooltip component rendering", () => {
79
72
  });
80
73
 
81
74
  it("should render the component with one row", async () => {
82
- defaultProps.elements = ["uno", "dos", "tres"];
83
- defaultProps.defaultElements = 1;
84
- defaultProps.elementsPerRow = 3;
85
-
86
75
  render(
87
76
  <ThemeProvider theme={parseTheme(globalTheme)}>
88
- <ElementsTooltip {...defaultProps} />
77
+ <ElementsTooltip {...makeProps({ elements: ["uno", "dos", "tres"], defaultElements: 1, elementsPerRow: 3 })} />
89
78
  </ThemeProvider>,
90
79
  );
91
80
 
@@ -12,13 +12,17 @@ import globalTheme from "@ax/themes/theme.json";
12
12
 
13
13
  afterEach(cleanup);
14
14
 
15
- const defaultProps = mock<IEmptyStateProps>();
15
+ // Props nuevos en cada test: antes se compartía un solo objeto mutable y el
16
+ // primer test, que comprueba el estado por defecto, fallaba en cuanto los
17
+ // siguientes le habían puesto title, message o button.
18
+ const makeProps = (overrides: Partial<IEmptyStateProps> = {}): IEmptyStateProps =>
19
+ Object.assign(mock<IEmptyStateProps>(), overrides);
16
20
 
17
21
  describe("EmptyState component rendering", () => {
18
22
  it("should render the component", () => {
19
23
  render(
20
24
  <ThemeProvider theme={parseTheme(globalTheme)}>
21
- <EmptyState {...defaultProps} />
25
+ <EmptyState {...makeProps()} />
22
26
  </ThemeProvider>,
23
27
  );
24
28
 
@@ -28,10 +32,9 @@ describe("EmptyState component rendering", () => {
28
32
  });
29
33
 
30
34
  it("should render the component with title", () => {
31
- defaultProps.title = "The title";
32
35
  render(
33
36
  <ThemeProvider theme={parseTheme(globalTheme)}>
34
- <EmptyState {...defaultProps} />
37
+ <EmptyState {...makeProps({ title: "The title" })} />
35
38
  </ThemeProvider>,
36
39
  );
37
40
 
@@ -41,10 +44,9 @@ describe("EmptyState component rendering", () => {
41
44
  });
42
45
 
43
46
  it("should render the component with message", () => {
44
- defaultProps.message = "A message";
45
47
  render(
46
48
  <ThemeProvider theme={parseTheme(globalTheme)}>
47
- <EmptyState {...defaultProps} />
49
+ <EmptyState {...makeProps({ message: "A message" })} />
48
50
  </ThemeProvider>,
49
51
  );
50
52
 
@@ -57,12 +59,10 @@ describe("EmptyState component rendering", () => {
57
59
  describe("EmptyState component events", () => {
58
60
  it("should trigger the onClick", () => {
59
61
  const actionFunc = vi.fn();
60
- defaultProps.button = "A button";
61
- defaultProps.action = actionFunc;
62
62
 
63
63
  render(
64
64
  <ThemeProvider theme={parseTheme(globalTheme)}>
65
- <EmptyState {...defaultProps} />
65
+ <EmptyState {...makeProps({ button: "A button", action: actionFunc })} />
66
66
  </ThemeProvider>,
67
67
  );
68
68