From 870b51df43b611e1c3988585b5a9a8f6ce14dd5a Mon Sep 17 00:00:00 2001 From: johnn1sbo3s Date: Wed, 15 Oct 2025 14:42:08 -0300 Subject: [PATCH 1/3] Implementa composable de gerenciamento de loadings das requests --- src/composables/useRequestLoadings.ts | 52 ++++ tests/composables/useRequestLoadings.test.ts | 268 +++++++++++++++++++ 2 files changed, 320 insertions(+) create mode 100644 src/composables/useRequestLoadings.ts create mode 100644 tests/composables/useRequestLoadings.test.ts diff --git a/src/composables/useRequestLoadings.ts b/src/composables/useRequestLoadings.ts new file mode 100644 index 0000000..7e00ba8 --- /dev/null +++ b/src/composables/useRequestLoadings.ts @@ -0,0 +1,52 @@ +import { computed, reactive, type Ref } from 'vue'; + +interface LoadingEntry { + id: string; + loading: Ref; +} + +export function useRequestLoadings() { + const entries = reactive([]); + + function registerRequestLoading(id: string, loadingRef: Ref): void { + if (!entries.find(e => e.id === id)) { + entries.push({ id, loading: loadingRef }); + return; + } + + throw new Error(`Loading com id ${id} já foi registrado.`); + } + + function unregisterRequestLoading(id: string): void { + const index = entries.findIndex(e => e.id === id); + if (index > -1) { + entries.splice(index, 1); + return; + } + + throw new Error(`Loading com id ${id} não foi registrado.`); + } + + const isAnyLoading = computed(() => { + const values = entries.map(e => e.loading); + if (values.length === 0) return false; + + const hasTrue = values.some(v => v === true); + const allNull = values.some(v => v === null); + + return hasTrue || allNull; + }); + + const isSettled = computed(() => { + const values = entries.map(e => e.loading); + if (values.length === 0) return true; + return values.every(v => v === false); + }); + + return { + registerRequestLoading, + unregisterRequestLoading, + isAnyLoading, + isSettled + }; +} \ No newline at end of file diff --git a/tests/composables/useRequestLoadings.test.ts b/tests/composables/useRequestLoadings.test.ts new file mode 100644 index 0000000..b722d88 --- /dev/null +++ b/tests/composables/useRequestLoadings.test.ts @@ -0,0 +1,268 @@ +import { ref } from 'vue'; +import { describe, it, expect } from 'vitest'; +import { useRequestLoadings } from '../../src/composables/useRequestLoadings'; + +describe('registerRequestLoading', () => { + it('should register a new loading reference with a unique id', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef = ref(false); + + registerRequestLoading('test-id', loadingRef); + + expect(isAnyLoading.value).toBe(false); + }); + + it('should throw an error when trying to register a duplicate id', () => { + const { registerRequestLoading } = useRequestLoadings(); + const loadingRef = ref(false); + + registerRequestLoading('duplicate-id', loadingRef); + + expect(() => registerRequestLoading('duplicate-id', loadingRef)).toThrow( + 'Loading com id duplicate-id já foi registrado.' + ); + }); + + it('should allow registering multiple different ids', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(false); + }); +}); + +describe('unregisterRequestLoading', () => { + it('should remove a registered loading reference', () => { + const { registerRequestLoading, unregisterRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef = ref(false); + + registerRequestLoading('test-id', loadingRef); + expect(isAnyLoading.value).toBe(false); + + unregisterRequestLoading('test-id'); + expect(isAnyLoading.value).toBe(false); + }); + + it('should throw an error when trying to unregister a non-existent id', () => { + const { unregisterRequestLoading } = useRequestLoadings(); + + expect(() => unregisterRequestLoading('non-existent-id')).toThrow( + 'Loading com id non-existent-id não foi registrado.' + ); + }); + + it('should correctly update isAnyLoading after removing a loading reference', () => { + const { registerRequestLoading, unregisterRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(true); + const loadingRef2 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(true); + + unregisterRequestLoading('id-1'); + expect(isAnyLoading.value).toBe(false); + }); +}); + +describe('isAnyLoading computed', () => { + it('should return false when there are no registered loadings', () => { + const { isAnyLoading } = useRequestLoadings(); + + expect(isAnyLoading.value).toBe(false); + }); + + it('should return false when all registered loadings are false', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(false); + }); + + it('should return true when at least one loading is true', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(true); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(true); + }); + + it('should return true when all loadings are null', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(null); + const loadingRef2 = ref(null); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(true); + }); + + it('should return true when some loadings are true and some are false', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(true); + const loadingRef3 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + registerRequestLoading('id-3', loadingRef3); + + expect(isAnyLoading.value).toBe(true); + }); + + it('should reactively update when loading references change', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef = ref(false); + + registerRequestLoading('reactive-test', loadingRef); + expect(isAnyLoading.value).toBe(false); + + loadingRef.value = true; + expect(isAnyLoading.value).toBe(true); + + loadingRef.value = false; + expect(isAnyLoading.value).toBe(false); + }); + + it('should handle mix of null and true values correctly', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(null); + const loadingRef2 = ref(true); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(true); + }); + + it('should handle mix of null and false values correctly', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef1 = ref(null); + const loadingRef2 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(true); + }); +}); + +describe('isSettled computed', () => { + it('should return true when there are no registered loadings', () => { + const { isSettled } = useRequestLoadings(); + + expect(isSettled.value).toBe(true); + }); + + it('should return true when all registered loadings are false', () => { + const { registerRequestLoading, isSettled } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isSettled.value).toBe(true); + }); + + it('should return false when at least one loading is true', () => { + const { registerRequestLoading, isSettled } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(true); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isSettled.value).toBe(false); + }); + + it('should return false when at least one loading is null', () => { + const { registerRequestLoading, isSettled } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(null); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isSettled.value).toBe(false); + }); + + it('should reactively update when loading references change', () => { + const { registerRequestLoading, isSettled } = useRequestLoadings(); + const loadingRef = ref(true); + + registerRequestLoading('reactive-test', loadingRef); + expect(isSettled.value).toBe(false); + + loadingRef.value = false; + expect(isSettled.value).toBe(true); + }); + + it('should return false when any value is not false', () => { + const { registerRequestLoading, isSettled } = useRequestLoadings(); + const loadingRef1 = ref(true); + const loadingRef2 = ref(null); + const loadingRef3 = ref(false); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + registerRequestLoading('id-3', loadingRef3); + + expect(isSettled.value).toBe(false); + }); +}); + +describe('integration tests', () => { + it('should work correctly with multiple register/unregister operations', () => { + const { registerRequestLoading, unregisterRequestLoading, isAnyLoading, isSettled } = useRequestLoadings(); + const loadingRef1 = ref(false); + const loadingRef2 = ref(true); + const loadingRef3 = ref(null); + + registerRequestLoading('id-1', loadingRef1); + registerRequestLoading('id-2', loadingRef2); + + expect(isAnyLoading.value).toBe(true); + expect(isSettled.value).toBe(false); + + unregisterRequestLoading('id-2'); + expect(isAnyLoading.value).toBe(false); + expect(isSettled.value).toBe(true); + + registerRequestLoading('id-3', loadingRef3); + expect(isAnyLoading.value).toBe(true); + expect(isSettled.value).toBe(false); + }); + + it('should handle rapid changes in loading states', () => { + const { registerRequestLoading, isAnyLoading } = useRequestLoadings(); + const loadingRef = ref(false); + + registerRequestLoading('rapid-change', loadingRef); + + loadingRef.value = true; + expect(isAnyLoading.value).toBe(true); + + loadingRef.value = false; + expect(isAnyLoading.value).toBe(false); + + loadingRef.value = null; + expect(isAnyLoading.value).toBe(true); + + loadingRef.value = false; + expect(isAnyLoading.value).toBe(false); + }); +}); \ No newline at end of file From f56d726a435334eff3820ee99cf9d77feb39e11b Mon Sep 17 00:00:00 2001 From: johnn1sbo3s Date: Wed, 15 Oct 2025 15:05:06 -0300 Subject: [PATCH 2/3] Altera nome da computada de isSettled para isLoadingSettled --- src/composables/useRequestLoadings.ts | 4 +-- tests/composables/useRequestLoadings.test.ts | 36 ++++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/composables/useRequestLoadings.ts b/src/composables/useRequestLoadings.ts index 7e00ba8..048b3c1 100644 --- a/src/composables/useRequestLoadings.ts +++ b/src/composables/useRequestLoadings.ts @@ -37,7 +37,7 @@ export function useRequestLoadings() { return hasTrue || allNull; }); - const isSettled = computed(() => { + const isLoadingSettled = computed(() => { const values = entries.map(e => e.loading); if (values.length === 0) return true; return values.every(v => v === false); @@ -47,6 +47,6 @@ export function useRequestLoadings() { registerRequestLoading, unregisterRequestLoading, isAnyLoading, - isSettled + isLoadingSettled }; } \ No newline at end of file diff --git a/tests/composables/useRequestLoadings.test.ts b/tests/composables/useRequestLoadings.test.ts index b722d88..3de8182 100644 --- a/tests/composables/useRequestLoadings.test.ts +++ b/tests/composables/useRequestLoadings.test.ts @@ -160,59 +160,59 @@ describe('isAnyLoading computed', () => { }); }); -describe('isSettled computed', () => { +describe('isLoadingSettled computed', () => { it('should return true when there are no registered loadings', () => { - const { isSettled } = useRequestLoadings(); + const { isLoadingSettled } = useRequestLoadings(); - expect(isSettled.value).toBe(true); + expect(isLoadingSettled.value).toBe(true); }); it('should return true when all registered loadings are false', () => { - const { registerRequestLoading, isSettled } = useRequestLoadings(); + const { registerRequestLoading, isLoadingSettled } = useRequestLoadings(); const loadingRef1 = ref(false); const loadingRef2 = ref(false); registerRequestLoading('id-1', loadingRef1); registerRequestLoading('id-2', loadingRef2); - expect(isSettled.value).toBe(true); + expect(isLoadingSettled.value).toBe(true); }); it('should return false when at least one loading is true', () => { - const { registerRequestLoading, isSettled } = useRequestLoadings(); + const { registerRequestLoading, isLoadingSettled } = useRequestLoadings(); const loadingRef1 = ref(false); const loadingRef2 = ref(true); registerRequestLoading('id-1', loadingRef1); registerRequestLoading('id-2', loadingRef2); - expect(isSettled.value).toBe(false); + expect(isLoadingSettled.value).toBe(false); }); it('should return false when at least one loading is null', () => { - const { registerRequestLoading, isSettled } = useRequestLoadings(); + const { registerRequestLoading, isLoadingSettled } = useRequestLoadings(); const loadingRef1 = ref(false); const loadingRef2 = ref(null); registerRequestLoading('id-1', loadingRef1); registerRequestLoading('id-2', loadingRef2); - expect(isSettled.value).toBe(false); + expect(isLoadingSettled.value).toBe(false); }); it('should reactively update when loading references change', () => { - const { registerRequestLoading, isSettled } = useRequestLoadings(); + const { registerRequestLoading, isLoadingSettled } = useRequestLoadings(); const loadingRef = ref(true); registerRequestLoading('reactive-test', loadingRef); - expect(isSettled.value).toBe(false); + expect(isLoadingSettled.value).toBe(false); loadingRef.value = false; - expect(isSettled.value).toBe(true); + expect(isLoadingSettled.value).toBe(true); }); it('should return false when any value is not false', () => { - const { registerRequestLoading, isSettled } = useRequestLoadings(); + const { registerRequestLoading, isLoadingSettled } = useRequestLoadings(); const loadingRef1 = ref(true); const loadingRef2 = ref(null); const loadingRef3 = ref(false); @@ -221,13 +221,13 @@ describe('isSettled computed', () => { registerRequestLoading('id-2', loadingRef2); registerRequestLoading('id-3', loadingRef3); - expect(isSettled.value).toBe(false); + expect(isLoadingSettled.value).toBe(false); }); }); describe('integration tests', () => { it('should work correctly with multiple register/unregister operations', () => { - const { registerRequestLoading, unregisterRequestLoading, isAnyLoading, isSettled } = useRequestLoadings(); + const { registerRequestLoading, unregisterRequestLoading, isAnyLoading, isLoadingSettled } = useRequestLoadings(); const loadingRef1 = ref(false); const loadingRef2 = ref(true); const loadingRef3 = ref(null); @@ -236,15 +236,15 @@ describe('integration tests', () => { registerRequestLoading('id-2', loadingRef2); expect(isAnyLoading.value).toBe(true); - expect(isSettled.value).toBe(false); + expect(isLoadingSettled.value).toBe(false); unregisterRequestLoading('id-2'); expect(isAnyLoading.value).toBe(false); - expect(isSettled.value).toBe(true); + expect(isLoadingSettled.value).toBe(true); registerRequestLoading('id-3', loadingRef3); expect(isAnyLoading.value).toBe(true); - expect(isSettled.value).toBe(false); + expect(isLoadingSettled.value).toBe(false); }); it('should handle rapid changes in loading states', () => { From b5dc8e6349dfcb5cb777c6fdf2a3deb6b19fa616 Mon Sep 17 00:00:00 2001 From: johnn1sbo3s Date: Wed, 15 Oct 2025 16:38:39 -0300 Subject: [PATCH 3/3] =?UTF-8?q?Atualiza=20vers=C3=A3o=20do=20projeto?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf56a2b..f42cb49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sysvale/show", - "version": "1.22.1", + "version": "1.23.0", "description": "A set of components used at Sysvale", "repository": { "type": "git",