);
}
diff --git a/packages/helpers/src/dom.test.js b/packages/helpers/src/dom.test.js
index d9d6b2e8..e3c64def 100644
--- a/packages/helpers/src/dom.test.js
+++ b/packages/helpers/src/dom.test.js
@@ -167,7 +167,7 @@ describe('helpers/dom', () => {
// Simulate the animation frame before the element is added
triggerAnimationFrame();
- expect(window.requestAnimationFrame).toHaveBeenCalledTimes(1);
+ expect(window.requestAnimationFrame).toHaveBeenCalledOnce();
expect(el.scrollIntoView).toHaveBeenCalledWith({ behavior: 'auto' });
});
diff --git a/packages/hooks/src/useTreeCollapse/useTreeCollapse.js b/packages/hooks/src/useTreeCollapse/useTreeCollapse.js
index b7006994..2049e804 100644
--- a/packages/hooks/src/useTreeCollapse/useTreeCollapse.js
+++ b/packages/hooks/src/useTreeCollapse/useTreeCollapse.js
@@ -1,5 +1,5 @@
import { getSubtreeSize } from '@barso/helpers';
-import { useCallback, useEffect, useRef, useState } from 'react';
+import { useEffect, useReducer, useRef } from 'react';
/**
* @typedef {Object} TreeNode
@@ -41,68 +41,47 @@ export function useTreeCollapse({
additionalBudget = 10,
defaultExpandedId = null,
} = {}) {
- const lastParamsRef = useRef({ totalBudget, minimalSubTree, defaultExpandedId });
-
- const [nodeStates, setNodeStates] = useState(() =>
- computeNodeStates({
- minimalSubTree,
- nodes,
- totalBudget,
- defaultExpandedId,
- }),
+ const [nodeStates, dispatch] = useReducer(
+ (previousState, action = {}) => {
+ switch (action.type) {
+ case 'EXPAND_NODE':
+ return expandChildren({ additionalBudget, minimalSubTree, previousState, ...action });
+ case 'COLLAPSE_NODE':
+ return collapseChildren({ previousState, ...action });
+ case 'UPDATE_STATE':
+ return computeNodeStates({ defaultExpandedId, minimalSubTree, nodes, totalBudget, previousState, ...action });
+ case 'RESET_STATE':
+ default:
+ return computeNodeStates({ defaultExpandedId, minimalSubTree, nodes, totalBudget, ...action });
+ }
+ },
+ { minimalSubTree, nodes, totalBudget, defaultExpandedId },
+ computeNodeStates,
);
+ const lastParamsRef = useRef();
+
useEffect(() => {
+ if (!lastParamsRef.current) {
+ lastParamsRef.current = { totalBudget, minimalSubTree, defaultExpandedId };
+ return;
+ }
+
const shouldUsePrevious =
lastParamsRef.current.totalBudget === totalBudget &&
lastParamsRef.current.minimalSubTree === minimalSubTree &&
lastParamsRef.current.defaultExpandedId === defaultExpandedId;
if (shouldUsePrevious) {
- setNodeStates((previousState) =>
- computeNodeStates({
- minimalSubTree,
- nodes,
- previousState,
- totalBudget,
- defaultExpandedId,
- }),
- );
+ dispatch({ type: 'UPDATE_STATE' });
} else {
lastParamsRef.current = { totalBudget, minimalSubTree, defaultExpandedId };
- setNodeStates(
- computeNodeStates({
- minimalSubTree,
- nodes,
- totalBudget,
- defaultExpandedId,
- }),
- );
+ dispatch({ type: 'RESET_STATE' });
}
}, [defaultExpandedId, nodes, minimalSubTree, totalBudget]);
- const handleExpand = useCallback(
- (targetId) => {
- setNodeStates((previousState) =>
- expandChildren({
- additionalBudget,
- minimalSubTree,
- previousState,
- targetId,
- }),
- );
- },
- [additionalBudget, minimalSubTree],
- );
-
- const handleCollapse = useCallback((targetId) => {
- setNodeStates((previousState) =>
- collapseChildren({
- previousState,
- targetId,
- }),
- );
- }, []);
+ const handleExpand = (targetId) => dispatch({ type: 'EXPAND_NODE', targetId });
+ const handleCollapse = (targetId) => dispatch({ type: 'COLLAPSE_NODE', targetId });
return {
handleCollapse,
diff --git a/packages/infra/src/logger/axiom-transport.test.js b/packages/infra/src/logger/axiom-transport.test.js
index ac196b35..81b078e2 100644
--- a/packages/infra/src/logger/axiom-transport.test.js
+++ b/packages/infra/src/logger/axiom-transport.test.js
@@ -4,10 +4,10 @@ const mocks = vi.hoisted(() => {
const waitUntil = vi.fn().mockImplementation((promise) => promise);
const ingest = vi.fn();
const flush = vi.fn().mockResolvedValue();
- const Axiom = vi.fn().mockImplementation(() => ({
- ingest,
- flush,
- }));
+ const Axiom = vi.fn().mockImplementation(function () {
+ this.ingest = ingest;
+ this.flush = flush;
+ });
return {
ingest,
@@ -102,8 +102,7 @@ describe('axiomTransport', () => {
await transport.flush();
- expect(mocks.waitUntil).toHaveBeenCalledWith(mocks.flush());
- expect(mocks.waitUntil).toHaveBeenCalledOnce();
+ expect(mocks.waitUntil).toHaveBeenCalledExactlyOnceWith(mocks.flush());
});
it('should flush with logs', async () => {
@@ -121,8 +120,7 @@ describe('axiomTransport', () => {
expect.objectContaining({ level: 'error', msg: 'test log 2' }),
);
- expect(mocks.waitUntil).toHaveBeenCalledWith(mocks.flush());
- expect(mocks.waitUntil).toHaveBeenCalledOnce();
+ expect(mocks.waitUntil).toHaveBeenCalledExactlyOnceWith(mocks.flush());
});
it('should not ingest invalid logs', async () => {
@@ -169,10 +167,10 @@ describe('axiomTransport', () => {
it('should continue logging even if an error occurs with Axiom', async () => {
const error = new Error('test error');
- mocks.Axiom.mockImplementationOnce(({ onError }) => ({
- ingest: mocks.ingest.mockImplementationOnce(() => onError(error)),
- flush: mocks.flush,
- }));
+ mocks.Axiom.mockImplementationOnce(function ({ onError }) {
+ this.ingest = mocks.ingest.mockImplementationOnce(() => onError(error));
+ this.flush = mocks.flush;
+ });
const transport = axiomTransport({ dataset, token });
diff --git a/packages/infra/src/logger/logger.test.js b/packages/infra/src/logger/logger.test.js
index bb7cef14..51611f4a 100644
--- a/packages/infra/src/logger/logger.test.js
+++ b/packages/infra/src/logger/logger.test.js
@@ -19,13 +19,14 @@ const token = 'test-token';
describe('infra/logger', () => {
const mocks = vi.hoisted(() => ({
axiomIngest: vi.fn(),
+ flush: vi.fn().mockResolvedValue(),
}));
vi.mock('@axiomhq/js', () => ({
- Axiom: vi.fn().mockImplementation(() => ({
- ingest: mocks.axiomIngest,
- flush: vi.fn().mockResolvedValue(),
- })),
+ Axiom: vi.fn().mockImplementation(function () {
+ this.ingest = mocks.axiomIngest;
+ this.flush = mocks.flush;
+ }),
}));
let stdoutSpy;
diff --git a/packages/ui/src/FormField/FormField.jsx b/packages/ui/src/FormField/FormField.jsx
index 4b46cb32..c5800980 100644
--- a/packages/ui/src/FormField/FormField.jsx
+++ b/packages/ui/src/FormField/FormField.jsx
@@ -57,10 +57,11 @@ export const FormField = forwardRef(
const inputProps = {
validationStatus: error ? 'error' : isValid ? 'success' : null,
inputMode,
- ref,
...props,
};
+ inputProps.ref = ref;
+
if (type === 'password') {
function focusAfterEnd() {
setTimeout(() => {
diff --git a/packages/ui/src/FormField/FormField.test.js b/packages/ui/src/FormField/FormField.test.js
index 592e391c..897a41a9 100644
--- a/packages/ui/src/FormField/FormField.test.js
+++ b/packages/ui/src/FormField/FormField.test.js
@@ -382,7 +382,7 @@ describe('ui', () => {
const handleClick = vi.fn();
render(