diff --git a/package-lock.json b/package-lock.json index 55b93e7..cb76daf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "react-redux": "^8.0.5", "react-transition-group": "^4.4.5", "redux-logger": "^4.0.0", - "webextension-polyfill-ts": "^0.26.0" + "webextension-polyfill": "^0.10.0" }, "devDependencies": { "@babel/core": "^7.8.7", @@ -44,7 +44,9 @@ "@types/redux-logger": "^3.0.9", "@types/remote-redux-devtools": "^0.5.4", "@types/shelljs": "^0.8.8", + "@types/sinon-chrome": "^2.2.11", "@types/wait-on": "^5.2.0", + "@types/webextension-polyfill": "^0.10.0", "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", "@xarc/run": "^1.0.4", @@ -3948,6 +3950,31 @@ "@types/node": "*" } }, + "node_modules/@types/sinon": { + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinon-chrome": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/@types/sinon-chrome/-/sinon-chrome-2.2.11.tgz", + "integrity": "sha512-hmpjlIDwIi8LLYdzZMh9+oj6k4mM7hD3dEC2a5vzYbNvIEIqDLxED8WhfroqLzLHLYV3ni5N1fLOEF0fmaFpqA==", + "dev": true, + "dependencies": { + "@types/chrome": "*", + "@types/sinon": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "node_modules/@types/sizzle": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", @@ -3989,6 +4016,12 @@ "@types/node": "*" } }, + "node_modules/@types/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==", + "dev": true + }, "node_modules/@types/yargs": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", @@ -22619,18 +22652,9 @@ } }, "node_modules/webextension-polyfill": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz", - "integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==" - }, - "node_modules/webextension-polyfill-ts": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill-ts/-/webextension-polyfill-ts-0.26.0.tgz", - "integrity": "sha512-XEFL+aYVEsm/d4RajVwP75g56c/w2aSHnPwgtUv8/nCzbLNSzRQIix6aj1xqFkA5yr7OIDkk3OD/QTnPp8ThYA==", - "deprecated": "This project has moved to @types/webextension-polyfill", - "dependencies": { - "webextension-polyfill": "^0.8.0" - } + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "node_modules/webidl-conversions": { "version": "7.0.0", @@ -26286,6 +26310,31 @@ "@types/node": "*" } }, + "@types/sinon": { + "version": "10.0.13", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.13.tgz", + "integrity": "sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ==", + "dev": true, + "requires": { + "@types/sinonjs__fake-timers": "*" + } + }, + "@types/sinon-chrome": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/@types/sinon-chrome/-/sinon-chrome-2.2.11.tgz", + "integrity": "sha512-hmpjlIDwIi8LLYdzZMh9+oj6k4mM7hD3dEC2a5vzYbNvIEIqDLxED8WhfroqLzLHLYV3ni5N1fLOEF0fmaFpqA==", + "dev": true, + "requires": { + "@types/chrome": "*", + "@types/sinon": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.2.tgz", + "integrity": "sha512-9GcLXF0/v3t80caGs5p2rRfkB+a8VBGLJZVih6CNFkx8IZ994wiKKLSRs9nuFwk1HevWs/1mnUmkApGrSGsShA==", + "dev": true + }, "@types/sizzle": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", @@ -26327,6 +26376,12 @@ "@types/node": "*" } }, + "@types/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==", + "dev": true + }, "@types/yargs": { "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.19.tgz", @@ -40480,17 +40535,9 @@ "dev": true }, "webextension-polyfill": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz", - "integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==" - }, - "webextension-polyfill-ts": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill-ts/-/webextension-polyfill-ts-0.26.0.tgz", - "integrity": "sha512-XEFL+aYVEsm/d4RajVwP75g56c/w2aSHnPwgtUv8/nCzbLNSzRQIix6aj1xqFkA5yr7OIDkk3OD/QTnPp8ThYA==", - "requires": { - "webextension-polyfill": "^0.8.0" - } + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "webidl-conversions": { "version": "7.0.0", diff --git a/package.json b/package.json index e82e5d4..284ffef 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "react-redux": "^8.0.5", "react-transition-group": "^4.4.5", "redux-logger": "^4.0.0", - "webextension-polyfill-ts": "^0.26.0" + "webextension-polyfill": "^0.10.0" }, "devDependencies": { "@babel/core": "^7.8.7", @@ -64,7 +64,9 @@ "@types/redux-logger": "^3.0.9", "@types/remote-redux-devtools": "^0.5.4", "@types/shelljs": "^0.8.8", + "@types/sinon-chrome": "^2.2.11", "@types/wait-on": "^5.2.0", + "@types/webextension-polyfill": "^0.10.0", "@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/parser": "^4.33.0", "@xarc/run": "^1.0.4", diff --git a/setupTests.ts b/setupTests.ts index 733372f..e03fd9a 100644 --- a/setupTests.ts +++ b/setupTests.ts @@ -1,4 +1,11 @@ import '@testing-library/jest-dom/extend-expect'; +import chrome from 'sinon-chrome'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +window.chrome = chrome; + +chrome.runtime.id = 'testid'; // https://github.com/mozilla/webextension-polyfill/issues/218#issuecomment-584936358 class BrowserMock { runtime = { diff --git a/src/components/MainList.test.tsx b/src/components/MainList.test.tsx index 50acbde..9ef54a5 100644 --- a/src/components/MainList.test.tsx +++ b/src/components/MainList.test.tsx @@ -2,29 +2,16 @@ import React from 'react'; import { renderWithProviders } from '../utils/test-utils'; import MainList from './MainList'; -type onClick = (event: React.MouseEvent) => void; describe('MainList', () => { - let disableLogging: onClick; - let enableLogging: onClick; let loggingEnabled: boolean; - let logoutUser: onClick; let totalTimeLoggedToday: string; beforeEach(() => { - disableLogging = jest.fn(); - enableLogging = jest.fn(); loggingEnabled = false; - logoutUser = jest.fn(); totalTimeLoggedToday = '1/1/1999'; }); it('should render properly', () => { const { container } = renderWithProviders( - , + , ); expect(container).toMatchInlineSnapshot(`
diff --git a/src/components/MainList.tsx b/src/components/MainList.tsx index 874b712..e5225e8 100644 --- a/src/components/MainList.tsx +++ b/src/components/MainList.tsx @@ -1,13 +1,13 @@ import React from 'react'; -import { useSelector } from 'react-redux'; +import { useSelector, useDispatch } from 'react-redux'; +import changeExtensionState from '../utils/changeExtensionState'; +import { configLogout, setLoggingEnabled } from '../reducers/configReducer'; +import { userLogout } from '../reducers/currentUser'; import { ReduxSelector } from '../types/store'; import { User } from '../types/user'; export interface MainListProps { - disableLogging: (event: React.MouseEvent) => void; - enableLogging: (event: React.MouseEvent) => void; loggingEnabled: boolean; - logoutUser: (event: React.MouseEvent) => void; totalTimeLoggedToday?: string; } const openOptionsPage = async (): Promise => { @@ -15,16 +15,34 @@ const openOptionsPage = async (): Promise => { }; export default function MainList({ - disableLogging, - enableLogging, loggingEnabled, - logoutUser, totalTimeLoggedToday, }: MainListProps): JSX.Element { + const dispatch = useDispatch(); + const user: User | undefined = useSelector( (selector: ReduxSelector) => selector.currentUser.user, ); + const logoutUser = async (): Promise => { + await browser.storage.sync.set({ apiKey: '' }); + dispatch(configLogout()); + dispatch(userLogout()); + await changeExtensionState('notSignedIn'); + }; + + const enableLogging = async (): Promise => { + dispatch(setLoggingEnabled(true)); + await browser.storage.sync.set({ loggingEnabled: true }); + await changeExtensionState('allGood'); + }; + + const disableLogging = async (): Promise => { + dispatch(setLoggingEnabled(false)); + await browser.storage.sync.set({ loggingEnabled: false }); + await changeExtensionState('notLogging'); + }; + return (
{user && ( diff --git a/src/components/NavBar.tsx b/src/components/NavBar.tsx index c003a07..50d3249 100644 --- a/src/components/NavBar.tsx +++ b/src/components/NavBar.tsx @@ -2,9 +2,8 @@ import React, { useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { configLogout, setApiKey } from '../reducers/configReducer'; import { userLogout } from '../reducers/currentUser'; -import { ReduxSelector } from '../types/store'; +import { ApiKeyReducer, ReduxSelector } from '../types/store'; import { User } from '../types/user'; -import config from '../config/config'; import apiKeyInvalid from '../utils/apiKey'; import { fetchUserData } from '../utils/user'; @@ -14,20 +13,20 @@ export default function NavBar(): JSX.Element { apiKeyError: '', loading: false, }); - useEffect(() => { - const fetch = async () => { - const { apiKey } = await browser.storage.sync.get({ apiKey: config.apiKey }); - setState({ ...state, apiKey }); - }; - - fetch(); - }, []); const dispatch = useDispatch(); + + const { apiKey: apiKeyFromRedux }: ApiKeyReducer = useSelector( + (selector: ReduxSelector) => selector.config, + ); const user: User | undefined = useSelector( (selector: ReduxSelector) => selector.currentUser.user, ); + useEffect(() => { + setState({ ...state, apiKey: apiKeyFromRedux }); + }, [apiKeyFromRedux]); + const signedInAs = () => { if (user) { return ( diff --git a/src/components/WakaTime.tsx b/src/components/WakaTime.tsx index ec756e2..9df0ec9 100644 --- a/src/components/WakaTime.tsx +++ b/src/components/WakaTime.tsx @@ -1,20 +1,13 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { ApiKeyReducer, ReduxSelector } from '../types/store'; -import config from '../config/config'; import { fetchUserData } from '../utils/user'; -import changeExtensionState from '../utils/changeExtensionState'; import NavBar from './NavBar'; import MainList from './MainList'; export default function WakaTime(): JSX.Element { const dispatch = useDispatch(); - const defaultState = { - loggingEnabled: config.loggingEnabled, - totalTimeLoggedToday: '0 minutes', - }; - const [state, setState] = useState(defaultState); const { apiKey: apiKeyFromRedux, loggingEnabled, @@ -25,53 +18,13 @@ export default function WakaTime(): JSX.Element { fetchUserData(apiKeyFromRedux, dispatch); }, []); - const disableLogging = async () => { - setState({ - ...state, - loggingEnabled: false, - }); - - await changeExtensionState('notLogging'); - - await browser.storage.sync.set({ - loggingEnabled: false, - }); - }; - - const enableLogging = async () => { - setState({ - ...state, - loggingEnabled: true, - }); - - await changeExtensionState('allGood'); - - await browser.storage.sync.set({ - loggingEnabled: true, - }); - }; - - const logoutUser = async () => { - await browser.storage.sync.set({ apiKey: '' }); - - setState(defaultState); - - await changeExtensionState('notSignedIn'); - }; - return (
- +
diff --git a/src/core/WakaTimeCore.ts b/src/core/WakaTimeCore.ts index e66dd1d..9f7923f 100644 --- a/src/core/WakaTimeCore.ts +++ b/src/core/WakaTimeCore.ts @@ -1,6 +1,6 @@ import axios, { AxiosResponse } from 'axios'; import moment from 'moment'; -import { Tabs } from 'webextension-polyfill-ts'; +import { Tabs } from 'webextension-polyfill'; import { AxiosUserResponse, User } from '../types/user'; import config from '../config/config'; import { SummariesPayload, GrandTotal } from '../types/summaries'; diff --git a/src/popup.tsx b/src/popup.tsx index 38c6453..1c127cd 100644 --- a/src/popup.tsx +++ b/src/popup.tsx @@ -14,13 +14,8 @@ const root = createRoot(container!); const store = createStore('WakaTime-Options'); checkCurrentUser(store)(30 * 1000); -const openOptions = async (): Promise => { - await browser.runtime.openOptionsPage(); -}; - root.render( -
Open options
, ); diff --git a/src/utils/changeExtensionIcon.ts b/src/utils/changeExtensionIcon.ts index 0ea34c2..a5a426f 100644 --- a/src/utils/changeExtensionIcon.ts +++ b/src/utils/changeExtensionIcon.ts @@ -1,4 +1,4 @@ -import { browser } from 'webextension-polyfill-ts'; +import browser from 'webextension-polyfill'; import config from '../config/config'; type ColorIconTypes = 'gray' | 'red' | 'white' | ''; diff --git a/src/utils/changeExtensionTooltip.ts b/src/utils/changeExtensionTooltip.ts index a01798e..ef4e4ba 100644 --- a/src/utils/changeExtensionTooltip.ts +++ b/src/utils/changeExtensionTooltip.ts @@ -1,4 +1,4 @@ -import { browser } from 'webextension-polyfill-ts'; +import browser from 'webextension-polyfill'; import config from '../config/config'; /**