Convert utility functions to TypeScript (#22658)

* Convert event-tracking to TypeScript

* Convert local-storage to TypeScript

* Convert mapSeries to TypeScript

* Convert SessionStorage to TypeScript

* Convert account-upgrade to TypeScript

* Convert isValidTeXFile to TypeScript

* Convert date functions to TypeScript

* Convert EventEmitter to TypeScript

* Convert isNetworkError to TypeScript

* Convert webpack-public-path to TypeScript

* Convert displayNameForUser to TypeScript

GitOrigin-RevId: 79c5a2d1101fcd520f3116f0f4af29d974189d94
This commit is contained in:
Alf Eaton
2025-01-15 11:20:18 +00:00
committed by Copybot
parent 386d6f8ffd
commit 2fbb4615f9
52 changed files with 203 additions and 210 deletions
@@ -1,6 +1,6 @@
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import isValidTeXFile from '../../../../main/is-valid-tex-file'
import { isValidTeXFile } from '../../../../main/is-valid-tex-file'
import { useEditorContext } from '../../../../shared/context/editor-context'
import { useProjectSettingsContext } from '../../context/project-settings-context'
import SettingsMenuSelect from './settings-menu-select'
@@ -3,7 +3,6 @@ import Icon from '../../../../shared/components/icon'
import { useCallback, useEffect, useState } from 'react'
import * as eventTracking from '../../../../infrastructure/event-tracking'
import StartFreeTrialButton from '../../../../shared/components/start-free-trial-button'
import { paywallPrompt } from '../../../../main/account-upgrade'
import { useFeatureFlag } from '@/shared/context/split-test-context'
function FeatureItem({ text }: { text: string }) {
@@ -22,7 +21,7 @@ export function OwnerPaywallPrompt() {
useEffect(() => {
eventTracking.send('subscription-funnel', 'editor-click-feature', 'history')
paywallPrompt('history')
eventTracking.sendMB('paywall-prompt', { 'paywall-type': 'history' })
}, [])
const handleFreeTrialClick = useCallback(() => {
@@ -0,0 +1,22 @@
import { User } from '@/features/history/services/types/shared'
import getMeta from '@/utils/meta'
import { formatUserName } from '@/features/history/utils/history-details'
export default function displayNameForUser(
user:
| (User & {
name?: string
})
| null
) {
if (user == null) {
return 'Anonymous'
}
if (user.id === getMeta('ol-user').id) {
return 'you'
}
if (user.name != null) {
return user.name
}
return formatUserName(user)
}
@@ -1,8 +1,8 @@
import displayNameForUser from '../../../ide/history/util/displayNameForUser'
import moment from 'moment/moment'
import ColorManager from '../../../ide/colors/ColorManager'
import { DocDiffChunk, Highlight } from '../services/types/doc'
import { TFunction } from 'i18next'
import displayNameForUser from './display-name-for-user'
export function highlightsFromDiffResponse(
chunks: DocDiffChunk[],
@@ -12,7 +12,7 @@ import useScopeEventEmitter from '@/shared/hooks/use-scope-event-emitter'
import useEventListener from '@/shared/hooks/use-event-listener'
import * as eventTracking from '@/infrastructure/event-tracking'
import useScopeValue from '@/shared/hooks/use-scope-value'
import isValidTeXFile from '@/main/is-valid-tex-file'
import { isValidTeXFile } from '@/main/is-valid-tex-file'
import localStorage from '@/infrastructure/local-storage'
import { useProjectContext } from '@/shared/context/project-context'
@@ -9,7 +9,7 @@ import {
prefetchLargeEnabled,
trackPdfDownloadEnabled,
} from './pdf-caching-flags'
import { isNetworkError } from '@/utils/isNetworkError'
import { isNetworkError } from '@/utils/is-network-error'
import { debugConsole } from '@/utils/debugging'
import { PDFJS } from './pdf-js'
@@ -1,7 +1,7 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useUserContext } from '../../../shared/context/user-context'
import { upgradePlan } from '../../../main/account-upgrade'
import { upgradePlan } from '@/main/account-upgrade'
import StartFreeTrialButton from '../../../shared/components/start-free-trial-button'
import Icon from '../../../shared/components/icon'
import { useFeatureFlag } from '../../../shared/context/split-test-context'
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next'
import Notification from '@/shared/components/notification'
import { upgradePlan } from '../../../../main/account-upgrade'
import { upgradePlan } from '@/main/account-upgrade'
import { useProjectContext } from '@/shared/context/project-context'
import { useUserContext } from '@/shared/context/user-context'
import { sendMB } from '@/infrastructure/event-tracking'
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next'
import Notification from '@/shared/components/notification'
import { upgradePlan } from '../../../../main/account-upgrade'
import { upgradePlan } from '@/main/account-upgrade'
import { linkSharingEnforcementDate } from '../../utils/link-sharing'
import { useProjectContext } from '@/shared/context/project-context'
import { useUserContext } from '@/shared/context/user-context'
@@ -3,7 +3,7 @@ import useScopeValue from '@/shared/hooks/use-scope-value'
import OLTooltip from '@/features/ui/components/ol/ol-tooltip'
import useTutorial from '@/shared/hooks/promotions/use-tutorial'
import { sendMB } from '../../../infrastructure/event-tracking'
import isValidTeXFile from '../../../main/is-valid-tex-file'
import { isValidTeXFile } from '../../../main/is-valid-tex-file'
import { useTranslation } from 'react-i18next'
import {
EditorSwitchBeginnerTooltip,
@@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'
import Icon from '../../../../shared/components/icon'
import { useProjectContext } from '../../../../shared/context/project-context'
import { useUserContext } from '../../../../shared/context/user-context'
import { startFreeTrial, upgradePlan } from '../../../../main/account-upgrade'
import { startFreeTrial, upgradePlan } from '@/main/account-upgrade'
import { memo } from 'react'
import { useFeatureFlag } from '@/shared/context/split-test-context'
import OLModal, {
@@ -47,7 +47,7 @@ import { setVisual } from '../extensions/visual/visual'
import { useFileTreePathContext } from '@/features/file-tree/contexts/file-tree-path'
import { useUserSettingsContext } from '@/shared/context/user-settings-context'
import { setDocName } from '@/features/source-editor/extensions/doc-name'
import isValidTexFile from '@/main/is-valid-tex-file'
import { isValidTeXFile } from '@/main/is-valid-tex-file'
import { captureException } from '@/infrastructure/error-reporter'
import grammarlyExtensionPresent from '@/shared/utils/grammarly'
import { DocumentContainer } from '@/features/ide-react/editor/document-container'
@@ -288,7 +288,7 @@ function useCodeMirrorScope(view: EditorView) {
const { previewByPath } = useFileTreePathContext()
const showVisual = visual && isValidTexFile(docName)
const showVisual = visual && isValidTeXFile(docName)
const visualRef = useRef({
previewByPath,
@@ -1,24 +0,0 @@
import getMeta from '@/utils/meta'
export default function displayNameForUser(user) {
if (user == null) {
return 'Anonymous'
}
if (user.id === getMeta('ol-user').id) {
return 'you'
}
if (user.name != null) {
return user.name
}
let name = [user.first_name, user.last_name]
.filter(n => n != null)
.join(' ')
.trim()
if (name === '') {
name = user.email.split('@')[0]
}
if (name == null || name === '') {
return '?'
}
return name
}
@@ -1,25 +1,40 @@
import sessionStorage from '../infrastructure/session-storage'
import sessionStorage from './session-storage'
import getMeta from '@/utils/meta'
type Segmentation = Record<
string,
string | number | boolean | undefined | unknown | any // TODO: RecurlyError
>
const CACHE_KEY = 'mbEvents'
function alreadySent(key) {
function alreadySent(key: string) {
const eventCache = sessionStorage.getItem(CACHE_KEY) || {}
return !!eventCache[key]
}
function markAsSent(key) {
function markAsSent(key: string) {
const eventCache = sessionStorage.getItem(CACHE_KEY) || {}
eventCache[key] = true
sessionStorage.setItem(CACHE_KEY, eventCache)
}
export function send(category, action, label, value) {
export function send(
category: string,
action: string,
label?: string,
value?: string
) {
if (typeof window.ga === 'function') {
window.ga('send', 'event', category, action, label, value)
}
}
export function sendOnce(category, action, label, value) {
export function sendOnce(
category: string,
action: string,
label: string,
value: string
) {
if (alreadySent(category)) return
if (typeof window.ga !== 'function') return
@@ -27,7 +42,7 @@ export function sendOnce(category, action, label, value) {
markAsSent(category)
}
export function sendMB(key, segmentation = {}) {
export function sendMB(key: string, segmentation: Segmentation = {}) {
if (!segmentation.page) {
segmentation.page = window.location.pathname
}
@@ -40,21 +55,28 @@ export function sendMB(key, segmentation = {}) {
}
}
export function sendMBOnce(key, segmentation = {}) {
export function sendMBOnce(key: string, segmentation: Segmentation = {}) {
if (alreadySent(key)) return
sendMB(key, segmentation)
markAsSent(key)
}
export function sendMBSampled(key, body = {}, rate = 0.01) {
export function sendMBSampled(
key: string,
segmentation: Segmentation = {},
rate = 0.01
) {
if (Math.random() < rate) {
sendMB(key, body)
sendMB(key, segmentation)
}
}
const sentOncePerPageLoad = new Set()
export function sendMBOncePerPageLoad(key, segmentation = {}) {
export function sendMBOncePerPageLoad(
key: string,
segmentation: Segmentation = {}
) {
if (sentOncePerPageLoad.has(key)) return
sendMB(key, segmentation)
sentOncePerPageLoad.add(key)
@@ -66,7 +88,7 @@ export function sendMBOncePerPageLoad(key, segmentation = {}) {
// @screen-sm: 768px;
export const isSmallDevice = window.screen.width < 768
function sendBeacon(key, data) {
function sendBeacon(key: string, data: Segmentation) {
if (!navigator || !navigator.sendBeacon) return
if (!getMeta('ol-ExposedSettings').isOverleaf) return
@@ -12,7 +12,11 @@ import { debugConsole } from '@/utils/debugging'
* @param {string?} key Key passed to the localStorage function (if any)
* @param {any?} value Value passed to the localStorage function (if any)
*/
const callSafe = function (fn, key, value) {
const callSafe = function (
fn: (...args: any) => any,
key?: string,
value?: any
) {
try {
return fn(key, value)
} catch (e) {
@@ -21,11 +25,12 @@ const callSafe = function (fn, key, value) {
}
}
const getItem = function (key) {
return JSON.parse(localStorage.getItem(key))
const getItem = function (key: string) {
const value = localStorage.getItem(key)
return value === null ? null : JSON.parse(value)
}
const setItem = function (key, value) {
const setItem = function (key: string, value: any) {
localStorage.setItem(key, JSON.stringify(value))
}
@@ -33,15 +38,15 @@ const clear = function () {
localStorage.clear()
}
const removeItem = function (key) {
const removeItem = function (key: string) {
return localStorage.removeItem(key)
}
const customLocalStorage = {
getItem: key => callSafe(getItem, key),
setItem: (key, value) => callSafe(setItem, key, value),
getItem: (key: string) => callSafe(getItem, key),
setItem: (key: string, value: any) => callSafe(setItem, key, value),
clear: () => callSafe(clear),
removeItem: key => callSafe(removeItem, key),
removeItem: (key: string) => callSafe(removeItem, key),
}
export default customLocalStorage
@@ -1,16 +0,0 @@
/**
* run `fn` in serie for all values, and resolve with an array of the results
* inspired by https://stackoverflow.com/a/50506360/1314820
* @template T the input array's item type
* @template V the `fn` function's return type
* @param {T[]} values
* @param {(item: T) => Promise<V>} fn
* @returns {V[]}
*/
export function mapSeries(values, fn) {
return values.reduce(async (promiseChain, value) => {
const chainResults = await promiseChain
const currentResult = await fn(value)
return [...chainResults, currentResult]
}, Promise.resolve([]))
}
@@ -0,0 +1,13 @@
/**
* run `fn` in series for all values, and resolve with an array of the results
*/
export const mapSeries = async <T = any, V = any>(
values: T[],
fn: (item: T) => Promise<V>
) => {
const output: V[] = []
for (const value of values) {
output.push(await fn(value))
}
return output
}
@@ -12,7 +12,11 @@ import { debugConsole } from '@/utils/debugging'
* @param {string?} key Key passed to the sessionStorage function (if any)
* @param {any?} value Value passed to the sessionStorage function (if any)
*/
const callSafe = function (fn, key, value) {
const callSafe = function (
fn: (...args: any) => any,
key?: string,
value?: any
) {
try {
return fn(key, value)
} catch (e) {
@@ -21,11 +25,12 @@ const callSafe = function (fn, key, value) {
}
}
const getItem = function (key) {
return JSON.parse(sessionStorage.getItem(key))
const getItem = function (key: string) {
const value = sessionStorage.getItem(key)
return value === null ? null : JSON.parse(value)
}
const setItem = function (key, value) {
const setItem = function (key: string, value: any) {
sessionStorage.setItem(key, JSON.stringify(value))
}
@@ -33,15 +38,15 @@ const clear = function () {
sessionStorage.clear()
}
const removeItem = function (key) {
const removeItem = function (key: string) {
return sessionStorage.removeItem(key)
}
const customSessionStorage = {
getItem: key => callSafe(getItem, key),
setItem: (key, value) => callSafe(setItem, key, value),
getItem: (key: string) => callSafe(getItem, key),
setItem: (key: string, value: any) => callSafe(setItem, key, value),
clear: () => callSafe(clear),
removeItem: key => callSafe(removeItem, key),
removeItem: (key: string) => callSafe(removeItem, key),
}
export default customSessionStorage
@@ -1,49 +0,0 @@
import * as eventTracking from '../infrastructure/event-tracking'
function startFreeTrial(source, version, $scope, variant) {
const eventSegmentation = { 'paywall-type': source }
if (variant) {
eventSegmentation.variant = variant
}
eventTracking.send('subscription-funnel', 'upgraded-free-trial', source)
eventTracking.sendMB('paywall-click', eventSegmentation)
const searchParams = new URLSearchParams({
itm_campaign: source,
})
if (version) {
searchParams.set('itm_content', version)
}
if ($scope) {
$scope.startedFreeTrial = true
}
window.open(`/user/subscription/choose-your-plan?${searchParams.toString()}`)
}
function upgradePlan(source, $scope) {
const w = window.open()
const go = function () {
if (typeof ga === 'function') {
ga('send', 'event', 'subscription-funnel', 'upgraded-plan', source)
}
const url = '/user/subscription'
if ($scope) {
$scope.startedFreeTrial = true
}
w.location = url
}
go()
}
function paywallPrompt(source) {
eventTracking.sendMB('paywall-prompt', { 'paywall-type': source })
}
export { startFreeTrial, upgradePlan, paywallPrompt }
@@ -0,0 +1,29 @@
import * as eventTracking from '../infrastructure/event-tracking'
export function startFreeTrial(source: string, variant?: string) {
const eventSegmentation: Record<string, string> = { 'paywall-type': source }
if (variant) {
eventSegmentation.variant = variant
}
eventTracking.send('subscription-funnel', 'upgraded-free-trial', source)
eventTracking.sendMB('paywall-click', eventSegmentation)
const searchParams = new URLSearchParams({
itm_campaign: source,
})
window.open(`/user/subscription/choose-your-plan?${searchParams.toString()}`)
}
export function upgradePlan(source: string) {
const openedWindow = window.open()
if (typeof window.ga === 'function') {
window.ga('send', 'event', 'subscription-funnel', 'upgraded-plan', source)
}
if (openedWindow) {
openedWindow.location = '/user/subscription'
}
}
@@ -1,6 +1,6 @@
import getMeta from '@/utils/meta'
function isValidTeXFile(filename) {
export const isValidTeXFile = (filename: string) => {
const validTeXFileRegExp = new RegExp(
`\\.(${getMeta('ol-ExposedSettings').validRootDocExtensions.join('|')})$`,
'i'
@@ -8,5 +8,3 @@ function isValidTeXFile(filename) {
return validTeXFileRegExp.test(filename)
}
export default isValidTeXFile
@@ -1,5 +1,5 @@
import './../utils/meta'
import './../utils/webpack-public-path'
import '../utils/webpack-public-path'
import './../infrastructure/error-reporter'
import '@/i18n'
import '../features/event-tracking'
@@ -1,5 +1,5 @@
import './../utils/meta'
import './../utils/webpack-public-path'
import '../utils/webpack-public-path'
import './../infrastructure/error-reporter'
import '@/i18n'
import ReactDOM from 'react-dom'
@@ -1,5 +1,5 @@
import './../utils/meta'
import './../utils/webpack-public-path'
import '../utils/webpack-public-path'
import './../infrastructure/error-reporter'
import '@/i18n'
import ReactDOM from 'react-dom'
@@ -1,6 +1,6 @@
import '../../marketing'
import './../../utils/meta'
import './../../utils/webpack-public-path'
import '../../utils/webpack-public-path'
import './../../infrastructure/error-reporter'
import '@/i18n'
import '../../features/settings/components/root'
@@ -1,5 +1,5 @@
import './../../../utils/meta'
import './../../../utils/webpack-public-path'
import '../../../utils/webpack-public-path'
import './../../../infrastructure/error-reporter'
import '@/i18n'
import '../../../features/event-tracking'
@@ -1,6 +1,6 @@
import { MouseEventHandler, useCallback, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { startFreeTrial } from '../../main/account-upgrade'
import { startFreeTrial } from '@/main/account-upgrade'
import * as eventTracking from '../../infrastructure/event-tracking'
import OLButton from '@/features/ui/components/ol/ol-button'
@@ -41,7 +41,7 @@ export default function StartFreeTrialButton({
handleClick(event)
}
startFreeTrial(source, null, null, variant)
startFreeTrial(source, variant)
},
[handleClick, source, variant]
)
@@ -7,11 +7,19 @@
// Remove a listener for the foo event with the bar namespace: .off 'foo.bar'
export default class EventEmitter {
events: Record<
string,
{
callback: (...args: any[]) => void
namespace: string
}[]
>
constructor() {
this.events = {}
}
on(event, callback) {
on(event: string, callback: (...args: any[]) => void) {
if (!this.events) {
this.events = {}
}
@@ -26,7 +34,7 @@ export default class EventEmitter {
})
}
off(event, cb) {
off(event?: string, callback?: (...args: any[]) => void) {
if (!this.events) {
this.events = {}
}
@@ -36,8 +44,10 @@ export default class EventEmitter {
if (!this.events[event]) {
this.events[event] = []
}
if (cb) {
this.events[event] = this.events[event].filter(e => e.callback !== cb)
if (callback) {
this.events[event] = this.events[event].filter(
e => e.callback !== callback
)
} else if (!namespace) {
// Clear all listeners for event
delete this.events[event]
@@ -53,7 +63,7 @@ export default class EventEmitter {
}
}
trigger(event, ...args) {
trigger(event: string, ...args: any[]) {
if (!this.events) {
this.events = {}
}
@@ -62,7 +72,7 @@ export default class EventEmitter {
}
}
emit(...args) {
this.trigger(...args)
emit(event: string, ...args: any[]) {
this.trigger(event, ...args)
}
}
@@ -1,6 +1,6 @@
import moment from 'moment'
export function formatDate(date, format) {
export function formatDate(date: moment.MomentInput, format?: string) {
if (!date) return 'N/A'
if (format == null) {
format = 'Do MMM YYYY, h:mm a'
@@ -8,6 +8,6 @@ export function formatDate(date, format) {
return moment(date).format(format)
}
export function fromNowDate(date) {
export function fromNowDate(date: moment.MomentInput | string) {
return moment(date).fromNow()
}
@@ -68,6 +68,6 @@ const NETWORK_ERRORS = [
'요청한 시간이 초과되었습니다.',
]
export function isNetworkError(err) {
return NETWORK_ERRORS.includes(err?.message)
export function isNetworkError(err?: Error) {
return err && NETWORK_ERRORS.includes(err.message)
}
@@ -1,7 +1,7 @@
import EmailsSection from '../../js/features/settings/components/emails-section'
import { UserEmailsProvider } from '../../js/features/settings/context/user-email-context'
import { LeaversSurveyAlert } from '../../js/features/settings/components/leavers-survey-alert'
import localStorage from '../../js/infrastructure/local-storage'
import localStorage from '@/infrastructure/local-storage'
import { bsVersionDecorator } from '../../../.storybook/utils/with-bootstrap-switcher'
export const SurveyAlert = () => {
@@ -1,5 +1,5 @@
import '../../helpers/bootstrap-3'
import localStorage from '../../../../frontend/js/infrastructure/local-storage'
import localStorage from '@/infrastructure/local-storage'
import PdfPreview from '../../../../frontend/js/features/pdf-preview/components/pdf-preview'
import { EditorProviders } from '../../helpers/editor-providers'
import { mockScope } from './scope'
@@ -1,17 +1,13 @@
import { screen, within } from '@testing-library/dom'
import { expect } from 'chai'
import sinon from 'sinon'
import fetchMock from 'fetch-mock'
import SettingsDocument from '../../../../../../frontend/js/features/editor-left-menu/components/settings/settings-document'
import * as isValidTeXFileModule from '../../../../../../frontend/js/main/is-valid-tex-file'
import { Folder } from '../../../../../../types/folder'
import { EditorLeftMenuProvider } from '@/features/editor-left-menu/components/editor-left-menu-context'
import { render } from '@testing-library/react'
import { EditorProviders } from '../../../../helpers/editor-providers'
describe('<SettingsDocument />', function () {
let isValidTeXFileStub: sinon.SinonStub
const rootFolder: Folder = {
_id: 'root-folder-id',
name: 'rootFolder',
@@ -25,15 +21,18 @@ describe('<SettingsDocument />', function () {
folders: [],
}
let originalSettings: typeof window.metaAttributesCache
beforeEach(function () {
isValidTeXFileStub = sinon
.stub(isValidTeXFileModule, 'default')
.returns(true)
originalSettings = window.metaAttributesCache.get('ol-ExposedSettings')
window.metaAttributesCache.set('ol-ExposedSettings', {
validRootDocExtensions: ['tex'],
})
})
afterEach(function () {
fetchMock.reset()
isValidTeXFileStub.restore()
window.metaAttributesCache.set('ol-ExposedSettings', originalSettings)
})
it('shows correct menu', async function () {
@@ -4,7 +4,7 @@ import { expect } from 'chai'
import { fireEvent, screen } from '@testing-library/react'
import LayoutDropdownButton from '../../../../../frontend/js/features/editor-navigation-toolbar/components/layout-dropdown-button'
import { renderWithEditorContext } from '../../../helpers/render-with-context'
import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
describe('<LayoutDropdownButton />', function () {
let openStub
@@ -1,19 +1,8 @@
/* eslint-disable
no-return-assign,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
import { expect } from 'chai'
import displayNameForUser from '@/features/history/utils/display-name-for-user'
import displayNameForUser from '../../../../../frontend/js/ide/history/util/displayNameForUser'
export default describe('displayNameForUser', function () {
const currentUsersId = 42
describe('displayNameForUser', function () {
const currentUsersId = 'user-a'
beforeEach(function () {
window.metaAttributesCache.set('ol-user', { id: currentUsersId })
})
@@ -7,7 +7,7 @@ import {
IndividualPlanSubscription,
} from '../../../../../types/project/dashboard/subscription'
import { DeepReadonly } from '../../../../../types/utils'
import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
import CurrentPlanWidget from '../../../../../frontend/js/features/project-list/components/current-plan-widget/current-plan-widget'
describe('<CurrentPlanWidget />', function () {
@@ -36,7 +36,7 @@ import { DeepPartial } from '../../../../../types/utils'
import { Project } from '../../../../../types/project/dashboard/api'
import GroupsAndEnterpriseBanner from '../../../../../frontend/js/features/project-list/components/notifications/groups-and-enterprise-banner'
import GroupSsoSetupSuccess from '../../../../../frontend/js/features/project-list/components/notifications/groups/group-sso-setup-success'
import localStorage from '../../../../../frontend/js/infrastructure/local-storage'
import localStorage from '@/infrastructure/local-storage'
import * as useLocationModule from '../../../../../frontend/js/shared/hooks/use-location'
import {
commonsSubscription,
@@ -4,7 +4,7 @@ import fetchMock from 'fetch-mock'
import sinon from 'sinon'
import ProjectListRoot from '../../../../../frontend/js/features/project-list/components/project-list-root'
import { renderWithProjectListContext } from '../helpers/render-with-context'
import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
import {
projectsData,
owner,
@@ -2,7 +2,7 @@ import sinon from 'sinon'
import { render, screen, fireEvent } from '@testing-library/react'
import { expect } from 'chai'
import SearchForm from '../../../../../frontend/js/features/project-list/components/search-form'
import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
import fetchMock from 'fetch-mock'
import { Filter } from '../../../../../frontend/js/features/project-list/context/project-list-context'
import { Tag } from '../../../../../app/src/Features/Tags/types'
@@ -5,7 +5,7 @@ import { projectsData } from '../../../../fixtures/projects-data'
import * as useLocationModule from '../../../../../../../../frontend/js/shared/hooks/use-location'
import { CompileAndDownloadProjectPDFButtonTooltip } from '../../../../../../../../frontend/js/features/project-list/components/table/cells/action-buttons/compile-and-download-project-pdf-button'
import fetchMock from 'fetch-mock'
import * as eventTracking from '../../../../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
describe('<CompileAndDownloadProjectPDFButton />', function () {
let assignStub: sinon.SinonStub
@@ -7,7 +7,7 @@ import {
resetProjectListContextFetch,
renderWithProjectListContext,
} from '../../helpers/render-with-context'
import * as eventTracking from '../../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
describe('<ProjectsActionModal />', function () {
const actionHandler = sinon.stub().resolves({})
@@ -3,8 +3,8 @@ import sinon from 'sinon'
import { fireEvent, screen, render } from '@testing-library/react'
import { UserEmailsProvider } from '../../../../../frontend/js/features/settings/context/user-email-context'
import { LeaversSurveyAlert } from '../../../../../frontend/js/features/settings/components/leavers-survey-alert'
import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
import localStorage from '../../../../../frontend/js/infrastructure/local-storage'
import * as eventTracking from '@/infrastructure/event-tracking'
import localStorage from '@/infrastructure/local-storage'
import fetchMock from 'fetch-mock'
function renderWithProvider() {
@@ -2,7 +2,7 @@ import { expect } from 'chai'
import sinon from 'sinon'
import { screen, fireEvent, render, waitFor } from '@testing-library/react'
import { IntegrationLinkingWidget } from '../../../../../../frontend/js/features/settings/components/linking/integration-widget'
import * as eventTracking from '../../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
describe('<IntegrationLinkingWidgetTest/>', function () {
const defaultProps = {
@@ -1,7 +1,7 @@
import { expect } from 'chai'
import sinon from 'sinon'
import { screen, render, waitFor } from '@testing-library/react'
import * as eventTracking from '../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
import SettingsPageRoot from '../../../../../frontend/js/features/settings/components/root'
import getMeta from '@/utils/meta'
@@ -14,7 +14,7 @@ import {
fakeUsersData,
unconfirmedCommonsUserData,
} from '../fixtures/test-user-email-data'
import localStorage from '../../../../../frontend/js/infrastructure/local-storage'
import localStorage from '@/infrastructure/local-storage'
const renderUserEmailsContext = () =>
renderHook(() => useUserEmailsContext(), {
@@ -1,6 +1,6 @@
import { expect } from 'chai'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import * as eventTracking from '../../../../../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
import { RecurlySubscription } from '../../../../../../../../types/subscription/dashboard/subscription'
import {
annualActiveSubscription,
@@ -1,7 +1,7 @@
import { expect } from 'chai'
import sinon from 'sinon'
import customLocalStorage from '../../../frontend/js/infrastructure/local-storage'
import customLocalStorage from '@/infrastructure/local-storage'
import { debugConsole } from '@/utils/debugging'
describe('localStorage', function () {
@@ -1,7 +1,7 @@
import { expect } from 'chai'
import { screen, render } from '@testing-library/react'
import Notification from '../../../../frontend/js/shared/components/notification'
import * as eventTracking from '../../../../frontend/js/infrastructure/event-tracking'
import * as eventTracking from '@/infrastructure/event-tracking'
import sinon from 'sinon'
describe('<Notification />', function () {
@@ -3,7 +3,7 @@ import { expect } from 'chai'
import { useEffect } from 'react'
import { render, screen } from '@testing-library/react'
import usePersistedState from '../../../../frontend/js/shared/hooks/use-persisted-state'
import localStorage from '../../../../frontend/js/infrastructure/local-storage'
import localStorage from '@/infrastructure/local-storage'
describe('usePersistedState', function () {
beforeEach(function () {
@@ -1,22 +1,11 @@
/* eslint-disable
max-len,
no-return-assign,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
import { expect } from 'chai'
import sinon from 'sinon'
import EventEmitter from '../../../frontend/js/utils/EventEmitter'
import EventEmitter from '@/utils/EventEmitter'
export default describe('EventEmitter', function () {
describe('EventEmitter', function () {
beforeEach(function () {
return (this.eventEmitter = new EventEmitter())
this.eventEmitter = new EventEmitter()
})
it('calls listeners', function () {
@@ -28,7 +17,7 @@ export default describe('EventEmitter', function () {
this.eventEmitter.trigger('foo')
expect(cb1).to.have.been.called
return expect(cb2).to.not.have.been.called
expect(cb2).to.not.have.been.called
})
it('calls multiple listeners', function () {
@@ -40,7 +29,7 @@ export default describe('EventEmitter', function () {
this.eventEmitter.trigger('foo')
expect(cb1).to.have.been.called
return expect(cb2).to.have.been.called
expect(cb2).to.have.been.called
})
it('calls listeners with namespace', function () {
@@ -52,7 +41,7 @@ export default describe('EventEmitter', function () {
this.eventEmitter.trigger('foo')
expect(cb1).to.have.been.called
return expect(cb2).to.have.been.called
expect(cb2).to.have.been.called
})
it('removes listeners', function () {
@@ -62,7 +51,7 @@ export default describe('EventEmitter', function () {
this.eventEmitter.trigger('foo')
return expect(cb).to.not.have.been.called
expect(cb).to.not.have.been.called
})
it('removes namespaced listeners', function () {
@@ -72,7 +61,7 @@ export default describe('EventEmitter', function () {
this.eventEmitter.trigger('foo')
return expect(cb).to.not.have.been.called
expect(cb).to.not.have.been.called
})
it('does not remove unnamespaced listeners if off called with namespace', function () {
@@ -85,6 +74,6 @@ export default describe('EventEmitter', function () {
this.eventEmitter.trigger('foo')
expect(cb1).to.have.been.called
return expect(cb2).to.not.have.been.called
expect(cb2).to.not.have.been.called
})
})
+2
View File
@@ -37,5 +37,7 @@ declare global {
store: ScopeValueStore
}
}
ga?: (...args: any) => void
gtag?: (...args: any) => void
}
}