From 5460adf6276262759efbedc4da4b9f4e216d3b87 Mon Sep 17 00:00:00 2001 From: htrinter Date: Tue, 21 Nov 2023 22:24:07 +0100 Subject: [PATCH 1/2] add deduplication feature --- src/browseraction/BrowserAction.vue | 4 +- .../__tests__/BrowserAction.spec.ts | 61 +++++++++++++++++-- .../__tests__/logic/load.spec.ts | 53 ++++++++++++---- src/browseraction/components/ActionBar.vue | 5 +- src/browseraction/components/OptionBar.vue | 15 +++++ src/browseraction/components/logic/load.ts | 21 ++++--- .../components/store/browser-storage.ts | 3 +- src/browseraction/components/store/store.ts | 5 ++ 8 files changed, 139 insertions(+), 28 deletions(-) diff --git a/src/browseraction/BrowserAction.vue b/src/browseraction/BrowserAction.vue index b589d29..92fe76a 100644 --- a/src/browseraction/BrowserAction.vue +++ b/src/browseraction/BrowserAction.vue @@ -13,13 +13,15 @@ Promise.all([ browser.storage.local.get(BrowserStorageKey.lazyload), browser.storage.local.get(BrowserStorageKey.random), browser.storage.local.get(BrowserStorageKey.reverse), - browser.storage.local.get(BrowserStorageKey.preserve) + browser.storage.local.get(BrowserStorageKey.preserve), + browser.storage.local.get(BrowserStorageKey.deduplicate) ]).then((data) => { store.urlList = data[0][BrowserStorageKey.urlList] ?? '' store.lazyLoadingChecked = data[1][BrowserStorageKey.lazyload] ?? false store.loadInRandomOrderChecked = data[2][BrowserStorageKey.random] ?? false store.loadInReverseOrderChecked = data[3][BrowserStorageKey.reverse] ?? false store.preserveInputChecked = data[4][BrowserStorageKey.preserve] ?? false + store.deduplicateURLsChecked = data[5][BrowserStorageKey.deduplicate] ?? false isStoredValuesLoaded.value = true }) diff --git a/src/browseraction/__tests__/BrowserAction.spec.ts b/src/browseraction/__tests__/BrowserAction.spec.ts index 98e8a7e..d784a38 100644 --- a/src/browseraction/__tests__/BrowserAction.spec.ts +++ b/src/browseraction/__tests__/BrowserAction.spec.ts @@ -35,6 +35,7 @@ describe('browser action', () => { expect(wrapper.text()).toContain('Load in random order') expect(wrapper.text()).toContain('Load in reverse order') expect(wrapper.text()).toContain('Preserve input') + expect(wrapper.text()).toContain('Ignore duplicate URLs') }) describe('features', () => { @@ -95,33 +96,77 @@ describe('browser action', () => { expect( (wrapper.find('input[type="checkbox"]#preserve').element as HTMLInputElement).checked ).toBeFalsy() + expect( + (wrapper.find('input[type="checkbox"]#deduplicate').element as HTMLInputElement).checked + ).toBeFalsy() }) const renderWithStoredValuesTestCases = [ { storeKey: BrowserStorageKey.urlList, value: 'foobar', - expectedStates: { lazyLoad: false, random: false, reverse: false, preserve: false } + expectedStates: { + lazyLoad: false, + random: false, + reverse: false, + preserve: false, + deduplicate: false + } }, { storeKey: BrowserStorageKey.lazyload, value: 'true', - expectedStates: { lazyLoad: true, random: false, reverse: false, preserve: false } + expectedStates: { + lazyLoad: true, + random: false, + reverse: false, + preserve: false, + deduplicate: false + } }, { storeKey: BrowserStorageKey.random, value: 'true', - expectedStates: { lazyLoad: false, random: true, reverse: false, preserve: false } + expectedStates: { + lazyLoad: false, + random: true, + reverse: false, + preserve: false, + deduplicate: false + } }, { storeKey: BrowserStorageKey.reverse, value: 'true', - expectedStates: { lazyLoad: false, random: false, reverse: true, preserve: false } + expectedStates: { + lazyLoad: false, + random: false, + reverse: true, + preserve: false, + deduplicate: false + } }, { storeKey: BrowserStorageKey.preserve, value: 'true', - expectedStates: { lazyLoad: false, random: false, reverse: false, preserve: true } + expectedStates: { + lazyLoad: false, + random: false, + reverse: false, + preserve: true, + deduplicate: false + } + }, + { + storeKey: BrowserStorageKey.deduplicate, + value: 'true', + expectedStates: { + lazyLoad: false, + random: false, + reverse: false, + preserve: false, + deduplicate: true + } } ] it.each(renderWithStoredValuesTestCases)( @@ -150,6 +195,9 @@ describe('browser action', () => { expect( (wrapper.find('input[type="checkbox"]#preserve').element as HTMLInputElement).checked ).toBe(expectedStates.preserve) + expect( + (wrapper.find('input[type="checkbox"]#deduplicate').element as HTMLInputElement).checked + ).toBe(expectedStates.deduplicate) } ) }) @@ -172,7 +220,8 @@ describe('browser action', () => { { checkboxId: 'lazyLoad', storeKey: BrowserStorageKey.lazyload }, { checkboxId: 'random', storeKey: BrowserStorageKey.random }, { checkboxId: 'reverse', storeKey: BrowserStorageKey.reverse }, - { checkboxId: 'preserve', storeKey: BrowserStorageKey.preserve } + { checkboxId: 'preserve', storeKey: BrowserStorageKey.preserve }, + { checkboxId: 'deduplicate', storeKey: BrowserStorageKey.deduplicate } ] it.each(storeCheckStateTestCases)( 'stores $checkboxId check state', diff --git a/src/browseraction/__tests__/logic/load.spec.ts b/src/browseraction/__tests__/logic/load.spec.ts index 372a105..9103861 100644 --- a/src/browseraction/__tests__/logic/load.spec.ts +++ b/src/browseraction/__tests__/logic/load.spec.ts @@ -1,6 +1,6 @@ import browser from 'webextension-polyfill' import { afterEach, describe, expect, it, vi } from 'vitest' -import { getTabCount, loadSites } from '@/browseraction/components/logic/load' +import { getTabCount, getURLsFromText, loadSites } from '@/browseraction/components/logic/load' vi.mock('webextension-polyfill', () => ({ default: { tabs: { create: vi.fn() }, runtime: { getURL: (val: string) => val } } @@ -16,7 +16,7 @@ describe('load tabs', () => { }) it('loads tabs in sequence', async () => { - loadSites(urlList, false, false, false) + loadSites(urlList, false, false, false, false) expect(browser.tabs.create).toHaveBeenNthCalledWith(1, { url: url1, @@ -26,10 +26,11 @@ describe('load tabs', () => { url: url2, active: false }) + expect(browser.tabs.create).toHaveBeenCalledTimes(2) }) it('lazy loads tabs', async () => { - loadSites(urlList, true, false, false) + loadSites(urlList, true, false, false, false) expect(browser.tabs.create).toHaveBeenCalledWith({ url: 'lazyloading.html#' + url1, @@ -39,16 +40,17 @@ describe('load tabs', () => { url: 'lazyloading.html#' + url2, active: false }) + expect(browser.tabs.create).toHaveBeenCalledTimes(2) }) it('loads tabs in random order', async () => { - loadSites(urlList, false, true, false) + loadSites(urlList, false, true, false, false) expect(browser.tabs.create).toHaveBeenCalledTimes(2) }) it('loads tabs in reverse order', async () => { - loadSites(urlList, false, false, true) + loadSites(urlList, false, false, true, false) expect(browser.tabs.create).toHaveBeenNthCalledWith(1, { url: url2, @@ -58,10 +60,25 @@ describe('load tabs', () => { url: url1, active: false }) + expect(browser.tabs.create).toHaveBeenCalledTimes(2) + }) + + it('loads tabs and deduplicate', async () => { + loadSites(`${urlList}\n${urlList}\n${urlList}\n${urlList}`, false, false, false, true) + + expect(browser.tabs.create).toHaveBeenNthCalledWith(1, { + url: url1, + active: false + }) + expect(browser.tabs.create).toHaveBeenNthCalledWith(2, { + url: url2, + active: false + }) + expect(browser.tabs.create).toHaveBeenCalledTimes(2) }) it('appends http protocol if protocol does not exist', async () => { - loadSites('test.de', false, false, true) + loadSites('test.de', false, false, true, false) expect(browser.tabs.create).toHaveBeenNthCalledWith(1, { url: 'http://test.de', @@ -70,10 +87,24 @@ describe('load tabs', () => { }) it('determines tab count correctly', () => { - expect(getTabCount('')).toBe('0') - expect(getTabCount(url1)).toBe('1') - expect(getTabCount(urlList)).toBe('2') - expect(getTabCount(`url1\n`.repeat(5000))).toBe('5000') - expect(getTabCount(`url1\n`.repeat(5001))).toBe('> 5000') + expect(getTabCount('', false)).toBe('0') + expect(getTabCount(url1, false)).toBe('1') + expect(getTabCount(urlList, false)).toBe('2') + expect(getTabCount(`url1\n`.repeat(5000), false)).toBe('5000') + expect(getTabCount(`url1\n`.repeat(5001), false)).toBe('> 5000') + expect(getTabCount(`${urlList}\n`.repeat(100), true)).toBe('2') + }) + + it('gets urls from text', () => { + expect(getURLsFromText('', false)).toEqual([]) + expect(getURLsFromText('\n\n', false)).toEqual([]) + expect(getURLsFromText(urlList, false)).toEqual([url1, url2]) + expect(getURLsFromText(`\n\n\n${urlList}\n\n\n${urlList}\n\n`, false)).toEqual([ + url1, + url2, + url1, + url2 + ]) + expect(getURLsFromText(`\n\n\n${urlList}\n\n\n${urlList}\n\n`, true)).toEqual([url1, url2]) }) }) diff --git a/src/browseraction/components/ActionBar.vue b/src/browseraction/components/ActionBar.vue index f22d942..687306a 100644 --- a/src/browseraction/components/ActionBar.vue +++ b/src/browseraction/components/ActionBar.vue @@ -32,7 +32,8 @@ export default { store.urlList, store.lazyLoadingChecked, store.loadInRandomOrderChecked, - store.loadInReverseOrderChecked + store.loadInReverseOrderChecked, + store.deduplicateURLsChecked ) }, setUrlListInputData() { @@ -41,7 +42,7 @@ export default { }, computed: { tabCount: function () { - return getTabCount(store.urlList) + return getTabCount(store.urlList, store.deduplicateURLsChecked) } } } diff --git a/src/browseraction/components/OptionBar.vue b/src/browseraction/components/OptionBar.vue index bca1b08..6a89685 100644 --- a/src/browseraction/components/OptionBar.vue +++ b/src/browseraction/components/OptionBar.vue @@ -34,6 +34,16 @@ import { store } from '@/browseraction/components/store/store' /> Load in reverse order +