@arquimedes.co/eureka-forms 3.0.63 → 3.0.64-fix-late-classifiers
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.
- package/dist/App/AppHooks.js +8 -0
- package/dist/App/AppHooks.test.js +8 -0
- package/dist/FormSteps/ClassifierSelectorStep/ClassifierSelectorStep.lateClassifiers.test.d.ts +1 -0
- package/dist/FormSteps/ClassifierSelectorStep/ClassifierSelectorStep.lateClassifiers.test.js +70 -0
- package/dist/FormSteps/ClassifierSelectorStep/MaterialClassifierSelectorStep/MaterialClassifierSelectorStep.js +3 -1
- package/package.json +1 -1
package/dist/App/AppHooks.js
CHANGED
|
@@ -158,6 +158,14 @@ export const useSetupApp = (isEmbedded, props) => {
|
|
|
158
158
|
idCurrentAgent,
|
|
159
159
|
handleConfirmed,
|
|
160
160
|
]);
|
|
161
|
+
// The host may resolve the classifiers asynchronously (the admin fetches them while the form is
|
|
162
|
+
// already mounted). `loadData` only copies the prop it saw when it ran, so patch the form whenever a
|
|
163
|
+
// new dictionary arrives — without re-running the load, which would reset what the user typed.
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
if (!classifiers || !form || form.classifiers === classifiers)
|
|
166
|
+
return;
|
|
167
|
+
setForm({ ...form, classifiers });
|
|
168
|
+
}, [classifiers, form]);
|
|
161
169
|
const reload = useCallback(() => {
|
|
162
170
|
if (!form)
|
|
163
171
|
return;
|
|
@@ -81,6 +81,14 @@ describe('AppHooks', function () {
|
|
|
81
81
|
expect(result.current.organization).toBeNull();
|
|
82
82
|
expect(result.current.branding).toBeUndefined();
|
|
83
83
|
});
|
|
84
|
+
test('picks up classifiers that arrive after the first render', async () => {
|
|
85
|
+
const classifier = { _id: 'tipo', name: 'Tipo de solicitud', children: [] };
|
|
86
|
+
const { result, rerender } = renderHookWithProviders((props) => useSetupApp(false, { formData: BaseForm, internal: true, classifiers: props.classifiers }), { initialProps: { classifiers: {} } });
|
|
87
|
+
await waitFor(() => expect(result.current.form).toBeTruthy());
|
|
88
|
+
expect(result.current.form?.classifiers).toEqual({});
|
|
89
|
+
rerender({ classifiers: { tipo: classifier } });
|
|
90
|
+
await waitFor(() => expect(result.current.form?.classifiers?.tipo).toEqual(classifier));
|
|
91
|
+
});
|
|
84
92
|
test('Apikey Default', async () => {
|
|
85
93
|
mocks.get.mockImplementation((a) => {
|
|
86
94
|
if (a === '/organization') {
|
package/dist/FormSteps/ClassifierSelectorStep/ClassifierSelectorStep.lateClassifiers.test.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import userEvent from '@testing-library/user-event';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import '@testing-library/jest-dom';
|
|
6
|
+
import { Provider } from 'react-redux';
|
|
7
|
+
import { FormProvider, useForm } from 'react-hook-form';
|
|
8
|
+
import { configureStore } from '@reduxjs/toolkit';
|
|
9
|
+
import { EurekaFormsReducer, defaultRootState } from '../../Utils/store';
|
|
10
|
+
import { RootApi } from '../../Utils/_api';
|
|
11
|
+
import FormStepTypes from '../../constants/FormStepTypes';
|
|
12
|
+
import { StoreContext } from '../../Utils/StoreContext';
|
|
13
|
+
import FormContext, { IdFormContext } from '../../Contexts/FormContext';
|
|
14
|
+
import SectionContext from '../../Contexts/SectionContext';
|
|
15
|
+
import MaterialProviders from '../../Utils/MaterialProviders';
|
|
16
|
+
import InternalFormStyle from '../../constants/InternalFormStyle';
|
|
17
|
+
import ClassifierSelectorStep from './ClassifierSelectorStep';
|
|
18
|
+
const ID_FORM = 'LATE_CLASSIFIERS_FORM';
|
|
19
|
+
const step = {
|
|
20
|
+
id: 'tipo-step',
|
|
21
|
+
idSection: 'SECTION_1',
|
|
22
|
+
stepPath: ['tipo-step'],
|
|
23
|
+
type: FormStepTypes.CLASSIFIER_SELECTOR,
|
|
24
|
+
idClassifier: 'tipo',
|
|
25
|
+
label: 'Tipo de solicitud',
|
|
26
|
+
description: '',
|
|
27
|
+
searchable: true,
|
|
28
|
+
options: {},
|
|
29
|
+
required: false,
|
|
30
|
+
size: 2,
|
|
31
|
+
};
|
|
32
|
+
/** The project's classifiers, as the host resolves them (asynchronously) and passes them to the form. */
|
|
33
|
+
const classifiers = {
|
|
34
|
+
tipo: { _id: 'tipo', name: 'Tipo de solicitud', children: ['bug', 'mejora'] },
|
|
35
|
+
bug: { _id: 'bug', name: 'Error / Bug', children: [] },
|
|
36
|
+
mejora: { _id: 'mejora', name: 'Propuesta de mejora', children: [] },
|
|
37
|
+
};
|
|
38
|
+
const form = {
|
|
39
|
+
firstSection: 'SECTION_1',
|
|
40
|
+
sections: {
|
|
41
|
+
SECTION_1: { id: 'SECTION_1', name: 'Sección 1', steps: ['tipo-step'], nextSection: null },
|
|
42
|
+
},
|
|
43
|
+
steps: { 'tipo-step': step },
|
|
44
|
+
confirmationMessage: { blocks: [], entityMap: {} },
|
|
45
|
+
showLink: false,
|
|
46
|
+
size: { blockSize: 200, blockNum: 4, spacingSize: 10 },
|
|
47
|
+
};
|
|
48
|
+
function makeStore() {
|
|
49
|
+
return configureStore({
|
|
50
|
+
reducer: { forms: EurekaFormsReducer, [RootApi.reducerPath]: RootApi.reducer },
|
|
51
|
+
preloadedState: { forms: { [ID_FORM]: { ...defaultRootState } } },
|
|
52
|
+
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(RootApi.middleware),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
function Harness({ store, formClassifiers, }) {
|
|
56
|
+
const methods = useForm({ mode: 'onTouched' });
|
|
57
|
+
return (_jsx(MaterialProviders, { formStyle: InternalFormStyle, children: _jsx(Provider, { store: store, context: StoreContext, children: _jsx(IdFormContext.Provider, { value: ID_FORM, children: _jsx(FormContext.Provider, { value: { ...form, classifiers: formClassifiers }, children: _jsx(SectionContext.Provider, { value: "SECTION_1", children: _jsx(FormProvider, { ...methods, children: _jsx(ClassifierSelectorStep, { step: step, editable: true }) }) }) }) }) }) }));
|
|
58
|
+
}
|
|
59
|
+
describe('ClassifierSelectorStep with classifiers that arrive after the first render', () => {
|
|
60
|
+
it('renders nothing while the classifiers are unknown, then the selector with its options', async () => {
|
|
61
|
+
const user = userEvent.setup();
|
|
62
|
+
const store = makeStore();
|
|
63
|
+
const { rerender } = render(_jsx(Harness, { store: store, formClassifiers: undefined }));
|
|
64
|
+
expect(screen.queryByRole('combobox')).not.toBeInTheDocument();
|
|
65
|
+
rerender(_jsx(Harness, { store: store, formClassifiers: classifiers }));
|
|
66
|
+
await user.click(await screen.findByRole('combobox'));
|
|
67
|
+
expect(await screen.findByRole('option', { name: 'Error / Bug' })).toBeInTheDocument();
|
|
68
|
+
expect(screen.getByRole('option', { name: 'Propuesta de mejora' })).toBeInTheDocument();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -50,8 +50,10 @@ function ClassifierSelectorStep({ step, editable }) {
|
|
|
50
50
|
};
|
|
51
51
|
}) ?? []);
|
|
52
52
|
},
|
|
53
|
+
// The classifiers dictionary can arrive after the first render (see useSetupApp), so the
|
|
54
|
+
// options must follow it, not only the dependency values.
|
|
53
55
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
54
|
-
[dependenciesValues]);
|
|
56
|
+
[dependenciesValues, classifier, form.classifiers]);
|
|
55
57
|
useEffect(() => {
|
|
56
58
|
if (value && !options?.find((option) => option.value === value?.value)) {
|
|
57
59
|
onChange('');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arquimedes.co/eureka-forms",
|
|
3
3
|
"repository": "git://github.com/Arquimede5/Eureka-Forms.git",
|
|
4
|
-
"version":
|
|
4
|
+
"version":"3.0.64-fix-late-classifiers",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"watch": "node node_modules/@typescript/native/bin/tsc --noEmit --watch --project tsconfig.app.json",
|
|
7
7
|
"start": "vite",
|