From c1625ac59e852217e4dd0ca7702a2e73be2d008b Mon Sep 17 00:00:00 2001 From: Eric Le Ponner Date: Wed, 28 Aug 2024 17:41:45 +0200 Subject: [PATCH 1/2] Re-worked Tabs.vue to make it work with mutating tab IDs and labels. Signed-off-by: Eric Le Ponner --- src/components/Tabs.vue | 82 ++++------ .../allowances/AllowancesSection.vue | 4 +- .../contract/ContractByteCodeSection.vue | 4 +- src/components/token/TokensSection.vue | 4 +- src/pages/AccountDetails.vue | 4 +- tests/unit/Tabs.spec.ts | 154 ++++++++++++++++++ 6 files changed, 198 insertions(+), 54 deletions(-) diff --git a/src/components/Tabs.vue b/src/components/Tabs.vue index d2528bdaa..75e21ad87 100644 --- a/src/components/Tabs.vue +++ b/src/components/Tabs.vue @@ -26,9 +26,9 @@
    -
  • - +
  • + {{ tabLabels[i] ?? tab }}
  • @@ -41,53 +41,43 @@ - diff --git a/src/components/allowances/AllowancesSection.vue b/src/components/allowances/AllowancesSection.vue index ef453e720..eb104ecd7 100644 --- a/src/components/allowances/AllowancesSection.vue +++ b/src/components/allowances/AllowancesSection.vue @@ -176,8 +176,8 @@ export default defineComponent({ const tabIds = ['hbar', 'token', 'nft'] const tabLabels = ['HBAR', 'Tokens', 'NFTs'] - const selectedTab = ref(AppStorage.getAccountAllowanceTab() ?? tabIds[0]) - const onUpdate = (tab: string) => { + const selectedTab = ref(AppStorage.getAccountAllowanceTab() ?? tabIds[0]) + const onUpdate = (tab: string|null) => { selectedTab.value = tab AppStorage.setAccountAllowanceTab(tab) switch (selectedTab.value) { diff --git a/src/components/contract/ContractByteCodeSection.vue b/src/components/contract/ContractByteCodeSection.vue index 385aa9c2c..feb2521e9 100644 --- a/src/components/contract/ContractByteCodeSection.vue +++ b/src/components/contract/ContractByteCodeSection.vue @@ -263,8 +263,8 @@ export default defineComponent({ const tabIds = ['abi', 'source', 'bytecode'] const tabLabels = ['ABI', 'Source', 'Bytecode'] - const selectedOption = ref(AppStorage.getContractByteCodeTab() ?? tabIds[0]) - const handleTabUpdate = (tab: string) => { + const selectedOption = ref(AppStorage.getContractByteCodeTab() ?? tabIds[0]) + const handleTabUpdate = (tab: string|null) => { selectedOption.value = tab AppStorage.setContractByteCodeTab(tab) } diff --git a/src/components/token/TokensSection.vue b/src/components/token/TokensSection.vue index 5b9d605ca..ee027e894 100644 --- a/src/components/token/TokensSection.vue +++ b/src/components/token/TokensSection.vue @@ -83,8 +83,8 @@ const accountId = computed(() => props.accountId) const tabIds = ['fungible', 'nfts'] const tabLabels = ['Fungible', 'NFTs'] -const selectedTab = ref(AppStorage.getAccountTokenTab() ?? tabIds[0]) -const onSelectTab = (tab: string) => { +const selectedTab = ref(AppStorage.getAccountTokenTab() ?? tabIds[0]) +const onSelectTab = (tab: string|null) => { selectedTab.value = tab AppStorage.setAccountTokenTab(tab) } diff --git a/src/pages/AccountDetails.vue b/src/pages/AccountDetails.vue index 1e38e3946..129ad4768 100644 --- a/src/pages/AccountDetails.vue +++ b/src/pages/AccountDetails.vue @@ -486,8 +486,8 @@ export default defineComponent({ const tabIds = ['transactions', 'contracts', 'rewards'] const tabLabels = ['Transactions', 'Created Contracts', 'Staking Rewards'] - const selectedTab = ref(AppStorage.getAccountOperationTab() ?? tabIds[0]) - const handleTabUpdate = (tab: string) => { + const selectedTab = ref(AppStorage.getAccountOperationTab() ?? tabIds[0]) + const handleTabUpdate = (tab: string|null) => { selectedTab.value = tab AppStorage.setAccountOperationTab(tab) } diff --git a/tests/unit/Tabs.spec.ts b/tests/unit/Tabs.spec.ts index be4b15e80..429309653 100644 --- a/tests/unit/Tabs.spec.ts +++ b/tests/unit/Tabs.spec.ts @@ -1,3 +1,5 @@ +// noinspection DuplicatedCode + /*- * * Hedera Mirror Node Explorer @@ -171,5 +173,157 @@ describe("Tabs.vue", () => { wrapper.unmount() }) + test("test with mutating IDs and labels", async () => { + + await router.push("/") // To avoid "missing required param 'network'" error + + // + // Stars with no tabs + // + + const tabIds = [] + const tabLabels = [] + + const wrapper = mount(Tabs, { + global: { + plugins: [router] + }, props: { + tabIds: tabIds, + tabLabels: tabLabels, + }, + }) + + await flushPromises() + + // console.log(wrapper.html()) + // console.log(wrapper.text()) + + const tabs = wrapper.findAll('li') + expect(tabs.length).toBe(0) + + // expect(tabs[selectedTab].attributes('class')).not.toContain('is-active') + + + // + // Add three tabs => tab1 is automatically selected + // + const tabIds2 = ['tab1', 'tab2', 'tab3'] + const tabLabels2 = ['label1', 'label2', 'label3'] + await wrapper.setProps({ + tabIds: tabIds2, + tabLabels: tabLabels2, + }) + + // console.log(wrapper.html()) + // console.log(wrapper.text()) + + const tabs2 = wrapper.findAll('li') + expect(tabs2.length).toBe(tabIds2.length) + expect(tabs2[0].text()).toContain("label1") + + expect(tabs2[0].attributes('class')).toContain('is-active') + + // + // Removes tab2 => tab1 remains selected + // + const tabIds3 = ['tab1', 'tab3'] + const tabLabels3 = ['label1', 'label3'] + await wrapper.setProps({ + tabIds: tabIds3, + tabLabels: tabLabels3, + }) + + // console.log(wrapper.html()) + // console.log(wrapper.text()) + + const tabs3 = wrapper.findAll('li') + expect(tabs3.length).toBe(tabIds3.length) + + expect(tabs3[0].attributes('class')).toContain('is-active') + expect(tabs3[0].text()).toContain("label1") + + // + // Removes tab1 => tab3 is selected + // + + const tabIds4 = ['tab3'] + const tabLabels4 = ['label3'] + await wrapper.setProps({ + tabIds: tabIds4, + tabLabels: tabLabels4, + }) + + // console.log(wrapper.html()) + // console.log(wrapper.text()) + + const tabs4 = wrapper.findAll('li') + expect(tabs4.length).toBe(tabIds4.length) + + expect(tabs4[0].attributes('class')).toContain('is-active') + expect(tabs4[0].text()).toContain("label3") + + + + wrapper.unmount() + }) + + test("test with interactive", async () => { + + await router.push("/") // To avoid "missing required param 'network'" error + + // + // Starts with ['tab1', 'tab2', 'tab3'] => default selection is tab1 + // + + const tabIds = ['tab1', 'tab2', 'tab3'] + const tabLabels = ['label1', 'label2', 'label3'] + + const wrapper = mount(Tabs, { + global: { + plugins: [router] + }, props: { + tabIds: tabIds, + tabLabels: tabLabels, + }, + }) + + await flushPromises() + + // console.log(wrapper.html()) + // console.log(wrapper.text()) + + const tabs = wrapper.findAll('li') + expect(tabs.length).toBe(tabIds.length) + + tabIds.forEach((id, index) => expect(wrapper.get('#tab-' + id).text()).toBe(tabLabels[index])) + + expect(tabs[0].attributes('class')).toContain('is-active') + + // + // Select tab3 interactively + // + + const anchors = wrapper.findAll('a') + await anchors[2].trigger("click") + expect(tabs[2].attributes('class')).toContain('is-active') + + + // + // Change tab list to ['tab2', 'tab3'] => tab3 remains selected + // + + const tabIds2 = ['tab2', 'tab3'] + const tabLabels2 = ['label2', 'label3'] + await wrapper.setProps({ + tabIds: tabIds2, + tabLabels: tabLabels2, + }) + const tabs2 = wrapper.findAll('li') + expect(tabs2.length).toBe(tabIds2.length) + + expect(tabs2[1].attributes('class')).toContain('is-active') + + wrapper.unmount() + }) }) From b12901eb29bc67b86e4bb02f9d848bf2219452c7 Mon Sep 17 00:00:00 2001 From: Eric Le Ponner Date: Fri, 30 Aug 2024 15:55:30 +0200 Subject: [PATCH 2/2] Tabs now takes no space when there are no tabs. Signed-off-by: Eric Le Ponner --- src/components/Tabs.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Tabs.vue b/src/components/Tabs.vue index 75e21ad87..e1abf9411 100644 --- a/src/components/Tabs.vue +++ b/src/components/Tabs.vue @@ -23,7 +23,7 @@