bt-core-app 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/extensions.json +3 -0
- package/README.md +45 -0
- package/index.html +13 -0
- package/package.json +39 -0
- package/public/vite.svg +1 -0
- package/src/assets/vue.svg +1 -0
- package/src/components/BT-Btn.vue +40 -0
- package/src/components/BT-Col.vue +36 -0
- package/src/components/BT-Span.vue +21 -0
- package/src/components/Dialog-Confirm.vue +47 -0
- package/src/components/Dialog-Select-Date.vue +89 -0
- package/src/components/Dialog-Select.vue +140 -0
- package/src/components/Dialog-Text.vue +59 -0
- package/src/composables/actions-tracker.ts +99 -0
- package/src/composables/actions.ts +354 -0
- package/src/composables/api.ts +471 -0
- package/src/composables/auth.ts +382 -0
- package/src/composables/cosmetics.ts +178 -0
- package/src/composables/csv.ts +198 -0
- package/src/composables/dates.ts +79 -0
- package/src/composables/demo.ts +25 -0
- package/src/composables/dialogs.ts +115 -0
- package/src/composables/document-meta.ts +40 -0
- package/src/composables/draggable.ts +189 -0
- package/src/composables/filters.ts +256 -0
- package/src/composables/forage.ts +49 -0
- package/src/composables/helpers.ts +694 -0
- package/src/composables/id.ts +20 -0
- package/src/composables/list.ts +601 -0
- package/src/composables/navigation.ts +214 -0
- package/src/composables/presets.ts +20 -0
- package/src/composables/pwa.ts +89 -0
- package/src/composables/resizable.ts +382 -0
- package/src/composables/rules.ts +40 -0
- package/src/composables/stores.ts +797 -0
- package/src/composables/track.ts +55 -0
- package/src/composables/urls.ts +11 -0
- package/src/core.ts +92 -0
- package/src/index.ts +16 -0
- package/src/types.ts +13 -0
- package/src/useApi.ts +68 -0
- package/src/vite-env.d.ts +1 -0
- package/test/api.test.ts +84 -0
- package/test/forage.test.ts +31 -0
- package/test/helpers.test.ts +231 -0
- package/test/navigation.test.ts +99 -0
- package/test/stores-last-update.test.ts +138 -0
- package/test/stores-session.test.ts +118 -0
- package/test/track.test.ts +29 -0
- package/test/utils.ts +15 -0
- package/tsconfig.json +33 -0
- package/tsconfig.node.json +11 -0
- package/vite.config.ts +19 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type MaybeRefOrGetter, type Ref, ref, toRef, toValue, watch } from "vue";
|
|
2
|
+
import { copyDeep } from '../composables/helpers';
|
|
3
|
+
|
|
4
|
+
export interface UseTrackerOptions {
|
|
5
|
+
propsToIgnore?: string[]
|
|
6
|
+
propsToTrack?: string[],
|
|
7
|
+
useTracker?: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function useTracker(data: MaybeRefOrGetter<any>, options?: UseTrackerOptions) { //propsToIgnore, propsToTrack) {
|
|
11
|
+
const isChanged = ref(false);
|
|
12
|
+
const asyncItem: Ref<any> = toRef(data);
|
|
13
|
+
let originalJSON = createJSON(toValue(data));
|
|
14
|
+
|
|
15
|
+
if (options?.useTracker !== false) {
|
|
16
|
+
watch(asyncItem, (v) => {
|
|
17
|
+
isChanged.value = createJSON(v) != originalJSON;
|
|
18
|
+
}, { deep: true })
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createJSON(dataItem: any) {
|
|
22
|
+
const copy = copyDeep(dataItem);
|
|
23
|
+
|
|
24
|
+
if (options != null) {
|
|
25
|
+
if (options.propsToIgnore != null) {
|
|
26
|
+
//delete from copy
|
|
27
|
+
options.propsToIgnore.forEach(k => {
|
|
28
|
+
delete copy[k];
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
else if (options.propsToTrack != null) {
|
|
32
|
+
//only keep these
|
|
33
|
+
const dataProps = Object.keys(dataItem)
|
|
34
|
+
dataProps.forEach(k => {
|
|
35
|
+
if (!options!.propsToTrack!.some(x => x == k)) {
|
|
36
|
+
delete copy[k]
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return JSON.stringify(copy);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function restart() {
|
|
46
|
+
originalJSON = createJSON(toValue(asyncItem));
|
|
47
|
+
isChanged.value = false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
asyncItem,
|
|
52
|
+
isChanged,
|
|
53
|
+
restartTracker: restart
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type Environment = 'production' | 'staging' | 'development'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ms: BASE_AUTH_URL, BASE_DATA_URL, WEB_APP_URL, Microservice, LOCAL_DB_NAME
|
|
5
|
+
* @param microservice
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function useUrl(microservice?: string) {
|
|
9
|
+
let ms = `VITE_${microservice ?? 'BASE_DATA_URL'}`
|
|
10
|
+
return import.meta.env[ms] as string | undefined
|
|
11
|
+
}
|
package/src/core.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { App } from 'vue'
|
|
2
|
+
import { createApi } from './composables/api'
|
|
3
|
+
import { createAuth, type GetAuthUrl, type AuthSubscription } from './composables/auth'
|
|
4
|
+
import { BaseCosmeticTheme, createCosmetics, UseCosmeticsOptions } from './composables/cosmetics'
|
|
5
|
+
import { createDates } from './composables/dates'
|
|
6
|
+
import { createDemo } from './composables/demo'
|
|
7
|
+
import { createFilters } from './composables/filters'
|
|
8
|
+
import { createNavigation, type NavigationItem } from './composables/navigation'
|
|
9
|
+
import { createPresets } from './composables/presets'
|
|
10
|
+
import { createPWA } from './composables/pwa'
|
|
11
|
+
import { createStoreBuilder } from './composables/stores'
|
|
12
|
+
import { RemovableRef } from '@vueuse/core'
|
|
13
|
+
|
|
14
|
+
import BTSpan from './components/BT-Span.vue'
|
|
15
|
+
|
|
16
|
+
export interface CoreApp {
|
|
17
|
+
install(app: App) : void
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CreateCoreOptions extends UseCosmeticsOptions<BaseCosmeticTheme> {
|
|
21
|
+
defaultCacheExpiryHours?: number
|
|
22
|
+
navItems?: NavigationItem[]
|
|
23
|
+
|
|
24
|
+
getAuthUrl: GetAuthUrl
|
|
25
|
+
presets: any
|
|
26
|
+
setCredentials?: (state: RemovableRef<any>, payload: any) => void
|
|
27
|
+
subscriptionOptions?: AuthSubscription[]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function createCore(options: CreateCoreOptions): CoreApp {
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
install(app: App) {
|
|
34
|
+
// const core = this
|
|
35
|
+
|
|
36
|
+
//register components
|
|
37
|
+
app.component('bt-span', BTSpan)
|
|
38
|
+
|
|
39
|
+
//define globals
|
|
40
|
+
// app.config.globalProperties.$btcore = core
|
|
41
|
+
|
|
42
|
+
const cosmetics = createCosmetics(options)
|
|
43
|
+
|
|
44
|
+
const demo = createDemo()
|
|
45
|
+
|
|
46
|
+
const navigation = createNavigation(options)
|
|
47
|
+
|
|
48
|
+
const presets = createPresets(options)
|
|
49
|
+
|
|
50
|
+
const auth = createAuth({
|
|
51
|
+
demo: demo,
|
|
52
|
+
getAuthItem: navigation.findItem,
|
|
53
|
+
getAuthUrl: options.getAuthUrl,
|
|
54
|
+
setCredentials: options.setCredentials,
|
|
55
|
+
subscriptionOptions: options.subscriptionOptions
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const api = createApi({
|
|
59
|
+
auth: auth,
|
|
60
|
+
findPath: navigation.findPath,
|
|
61
|
+
useBearerToken: true
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const dates = createDates({
|
|
65
|
+
getTimeZone: auth.getTimeZone
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const filters = createFilters({
|
|
69
|
+
dates: dates
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const pwa = createPWA()
|
|
73
|
+
|
|
74
|
+
const storeBuilder = createStoreBuilder({
|
|
75
|
+
api,
|
|
76
|
+
auth
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
//provide
|
|
80
|
+
app.provide('bt-api', api)
|
|
81
|
+
app.provide('bt-auth', auth)
|
|
82
|
+
app.provide('bt-cosmetics', cosmetics)
|
|
83
|
+
app.provide('bt-dates', dates)
|
|
84
|
+
app.provide('bt-demo', demo)
|
|
85
|
+
app.provide('bt-filters', filters)
|
|
86
|
+
app.provide('bt-navigation', navigation)
|
|
87
|
+
app.provide('bt-presets', presets)
|
|
88
|
+
app.provide('bt-pwa', pwa)
|
|
89
|
+
app.provide('bt-store', storeBuilder)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './composables/actions-tracker'
|
|
2
|
+
export * from './composables/actions'
|
|
3
|
+
export * from './composables/demo'
|
|
4
|
+
export * from './composables/document-meta'
|
|
5
|
+
export * from './composables/draggable'
|
|
6
|
+
export * from './composables/forage'
|
|
7
|
+
export * from './composables/helpers'
|
|
8
|
+
export * from './composables/id'
|
|
9
|
+
export * from './composables/list'
|
|
10
|
+
export * from './composables/resizable'
|
|
11
|
+
export * from './composables/rules'
|
|
12
|
+
export * from './composables/stores'
|
|
13
|
+
export * from './composables/track'
|
|
14
|
+
export * from './composables/urls'
|
|
15
|
+
export * from './useApi'
|
|
16
|
+
export * from './core'
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Inline: merges toolbars | much more compact | hides navigation
|
|
3
|
+
Page: shows navigation and page settings
|
|
4
|
+
Blade: shows blade minimize, maximize, close, and pins as a column
|
|
5
|
+
Free-moving: show blade as draggable and resizable with minimize, maximize, and close and pinning
|
|
6
|
+
*/
|
|
7
|
+
export type BladeVariant = 'page' | 'blade' | 'freestyle' | 'inline' | 'pane'
|
|
8
|
+
|
|
9
|
+
export type BladeMode = 'new' | 'view' | 'edit'
|
|
10
|
+
|
|
11
|
+
export interface BaseModel {
|
|
12
|
+
id?: string
|
|
13
|
+
}
|
package/src/useApi.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { inject } from 'vue'
|
|
2
|
+
// import { BTActions } from './composables/actions'
|
|
3
|
+
import { BTAuth } from './composables/auth'
|
|
4
|
+
import { BTApi } from './composables/api'
|
|
5
|
+
import { BTCosmetics } from './composables/cosmetics'
|
|
6
|
+
import { BTDates } from './composables/dates'
|
|
7
|
+
import { BTDemo } from './composables/demo'
|
|
8
|
+
import { BTFilters } from './composables/filters'
|
|
9
|
+
import { BTNavigation } from './composables/navigation'
|
|
10
|
+
import { BTPresets } from './composables/presets'
|
|
11
|
+
import { BTPWA } from './composables/pwa'
|
|
12
|
+
import { BTStore, CreateStoreOptions } from './composables/stores'
|
|
13
|
+
|
|
14
|
+
// /**returns a new instance */
|
|
15
|
+
// export function useActions(): BTActions {
|
|
16
|
+
// return inject('bt-actions')!
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
/**returns a singleton */
|
|
20
|
+
export function useApi(): BTApi {
|
|
21
|
+
return inject('bt-api')!
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**returns a singleton */
|
|
25
|
+
export function useAuth(): BTAuth {
|
|
26
|
+
return inject('bt-auth')!
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**returns a singleton */
|
|
30
|
+
export function useCosmetics(): BTCosmetics {
|
|
31
|
+
return inject('bt-cosmetics')!
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**returns a singleton */
|
|
35
|
+
export function useDates(): BTDates {
|
|
36
|
+
return inject('bt-dates')!
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**returns a singleton */
|
|
40
|
+
export function useDemo(): BTDemo {
|
|
41
|
+
return inject('bt-demo')!
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**returns a singleton */
|
|
45
|
+
export function useFilters(): BTFilters {
|
|
46
|
+
return inject('bt-filters')!
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**returns a singleton */
|
|
50
|
+
export function useNavigation(): BTNavigation {
|
|
51
|
+
return inject('bt-navigation')!
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**returns a singleton */
|
|
55
|
+
export function usePresets(preset?: string): any {
|
|
56
|
+
const p = inject('bt-presets')! as BTPresets
|
|
57
|
+
return p.usePresets(preset)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**returns a singleton */
|
|
61
|
+
export function usePWA(): BTPWA {
|
|
62
|
+
return inject('bt-pwa')!
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**returns a new instance */
|
|
66
|
+
export function useStore(): (opt: CreateStoreOptions) => BTStore {
|
|
67
|
+
return inject('bt-store')!
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
package/test/api.test.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { describe, test, expect, afterAll, afterEach, beforeAll } from 'vitest'
|
|
2
|
+
import { createApi } from '../src/composables/api'
|
|
3
|
+
import { setupServer } from 'msw/node'
|
|
4
|
+
import { http, HttpResponse } from 'msw'
|
|
5
|
+
|
|
6
|
+
const handlers = [
|
|
7
|
+
http.get('https://test-api/get/1', () => {
|
|
8
|
+
return HttpResponse.json({
|
|
9
|
+
data: { test: 'a' },
|
|
10
|
+
count: 0,
|
|
11
|
+
filters: ['test']
|
|
12
|
+
})
|
|
13
|
+
}),
|
|
14
|
+
http.get('https://test-api/get/2', () => {
|
|
15
|
+
return new HttpResponse('not found', {
|
|
16
|
+
status: 304
|
|
17
|
+
})
|
|
18
|
+
}),
|
|
19
|
+
http.get('https://test-api/getAll', () => {
|
|
20
|
+
return HttpResponse.json({
|
|
21
|
+
data: [{ test: 'a' }, { test: 'b' }],
|
|
22
|
+
count: 2,
|
|
23
|
+
filters: ['test', 'test two']
|
|
24
|
+
})
|
|
25
|
+
}),
|
|
26
|
+
http.post('https://test-api/post', () => {
|
|
27
|
+
return HttpResponse.json({ data: { test: 'b' } })
|
|
28
|
+
}),
|
|
29
|
+
http.patch('https://test-api/patch', () => {
|
|
30
|
+
return HttpResponse.json({ data: { test: 'c' } })
|
|
31
|
+
})
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const server = setupServer(...handlers)
|
|
35
|
+
|
|
36
|
+
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
|
|
37
|
+
|
|
38
|
+
afterAll(() => server.close())
|
|
39
|
+
|
|
40
|
+
afterEach(() => server.resetHandlers())
|
|
41
|
+
|
|
42
|
+
describe('default api', () => {
|
|
43
|
+
const api = createApi({
|
|
44
|
+
findPath: () => 'https://test-api/',
|
|
45
|
+
defaultThrowError: false
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('get', async () => {
|
|
49
|
+
const res = await api.get<any>({ additionalUrl: 'get', id: '1', nav: 'test' })
|
|
50
|
+
expect(res).not.toBeNull()
|
|
51
|
+
expect(res.data.test).toEqual('a')
|
|
52
|
+
expect(res.filters[0]).toEqual('test')
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('get fails', async () => {
|
|
56
|
+
const res = await api.get<any>({ additionalUrl: 'get', id: '2', nav: 'test' })
|
|
57
|
+
expect(res.status).toEqual(304)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('getAll', async () => {
|
|
61
|
+
const res = await api.get<any>({ additionalUrl: 'getAll', nav: 'test' })
|
|
62
|
+
expect(res).not.toBeNull()
|
|
63
|
+
expect(res.data.length).toEqual(2)
|
|
64
|
+
expect(res.count).toEqual(2)
|
|
65
|
+
expect(res.filters[0]).toEqual('test')
|
|
66
|
+
expect(res.filters[1]).toEqual('test two')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
test('post', async () => {
|
|
70
|
+
const res = await api.post<any>({ additionalUrl: 'post', nav: 'test', data: { data: 'a' }})
|
|
71
|
+
expect(res).not.toBeNull()
|
|
72
|
+
expect(res).toEqual({ data: { test: 'b' } })
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('patch', async () => {
|
|
76
|
+
const res = await api.patch<any>({ additionalUrl: 'patch', nav: 'test', data: { data: 'a' }})
|
|
77
|
+
expect(res).not.toBeNull()
|
|
78
|
+
expect(res).toEqual({ data: { test: 'c' } })
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// describe('default api fails', () => {
|
|
83
|
+
|
|
84
|
+
// })
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest'
|
|
2
|
+
import { withSetup } from './utils'
|
|
3
|
+
import { useLocalDb } from '../src/composables/forage'
|
|
4
|
+
|
|
5
|
+
describe('foraging', () => {
|
|
6
|
+
const [db] = withSetup(() => useLocalDb())
|
|
7
|
+
|
|
8
|
+
test('local db exists', () => {
|
|
9
|
+
expect(db).not.toBeNull()
|
|
10
|
+
expect(db._config.name).toEqual('Db_undefined')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
// describe('local cache', () => {
|
|
16
|
+
// const [cache] = withSetup(() => useLocalCache())
|
|
17
|
+
|
|
18
|
+
// test('save', async () => {
|
|
19
|
+
// expect(cache).not.toBeNull()
|
|
20
|
+
|
|
21
|
+
// await cache.saveAsync({ test: 'a' }, 'test-key')
|
|
22
|
+
|
|
23
|
+
// const res = await cache.getAsync('test-key')
|
|
24
|
+
|
|
25
|
+
// expect(res.test).toEqual('a')
|
|
26
|
+
|
|
27
|
+
// await cache.clearAsync()
|
|
28
|
+
|
|
29
|
+
// const none = await cache.getAsync('test-key')
|
|
30
|
+
// })
|
|
31
|
+
// })
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { nestedValue, toCompareString, hasSearch, deepSelect, containsSearch, copyItemByAlphabet, copyDeep, csvContains, toggleCSV, roundTo, isArrayOfLength, isLengthyArray, addWeekday, removeWeekday, appendUrl, getAreaAround, getAreaToLeft, getAreaToRight, getLocationLine, capitalizeWords, fromCamelCase, toCamelCase, weekdayValue, weekdayShortName, containsWeekday, validEmail } from '../src/composables/helpers'
|
|
2
|
+
import { describe, expect, test } from 'vitest'
|
|
3
|
+
|
|
4
|
+
describe("helpers", () => {
|
|
5
|
+
|
|
6
|
+
test('append url', () => {
|
|
7
|
+
expect(appendUrl('https://test.com/', '/test')).toEqual('https://test.com/test')
|
|
8
|
+
expect(appendUrl('https://test.com', 'test')).toEqual('https://test.com/test')
|
|
9
|
+
expect(appendUrl('https://test.com/', 'test')).toEqual('https://test.com/test')
|
|
10
|
+
expect(appendUrl('https://test.com', '/test')).toEqual('https://test.com/test')
|
|
11
|
+
expect(appendUrl('https://test.com///', '///test')).toEqual('https://test.com/test')
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('get area around', () => {
|
|
15
|
+
//starts with top left and goes anti-clockwise
|
|
16
|
+
expect(getAreaAround({ lat: 0, lng: 0 }, 1)).toEqual([{ lat: -1, lng: 1 },{ lat: -1, lng: -1 },{ lat: 1, lng: -1 },{ lat: 1, lng: 1 }])
|
|
17
|
+
expect(getAreaAround({ lat: 0, lng: 0 }, 2)).toEqual([{ lat: -2, lng: 2 },{ lat: -2, lng: -2 },{ lat: 2, lng: -2 },{ lat: 2, lng: 2 }])
|
|
18
|
+
expect(getAreaAround({ lat: 2, lng: 6 }, 1)).toEqual([{ lat: 1, lng: 7 },{ lat: 1, lng: 5 },{ lat: 3, lng: 5 },{ lat: 3, lng: 7 }])
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('get area to left', () => {
|
|
22
|
+
//starts with top left and goes anti-clockwise
|
|
23
|
+
expect(getAreaToLeft({ lat: 0, lng: 0 }, 1)).toEqual([{ lat: -2, lng: 1 },{ lat: -2, lng: -1 },{ lat: 0, lng: -1 },{ lat: 0, lng: 1 }])
|
|
24
|
+
expect(getAreaToLeft({ lat: 0, lng: 0 }, 2)).toEqual([{ lat: -4, lng: 2 },{ lat: -4, lng: -2 },{ lat: 0, lng: -2 },{ lat: 0, lng: 2 }])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('get area to right', () => {
|
|
28
|
+
//starts with top left and goes anti-clockwise
|
|
29
|
+
expect(getAreaToRight({ lat: 0, lng: 0 }, 1)).toEqual([{ lat: 0, lng: 1 },{ lat: 0, lng: -1 },{ lat: 2, lng: -1 },{ lat: 2, lng: 1 }])
|
|
30
|
+
expect(getAreaToRight({ lat: 2, lng: 0 }, 2)).toEqual([{ lat: 2, lng: 2 },{ lat: 2, lng: -2 },{ lat: 6, lng: -2 },{ lat: 6, lng: 2 }])
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('get location line', () => {
|
|
34
|
+
expect(getLocationLine(null)).toEqual('')
|
|
35
|
+
expect(getLocationLine({ streetNumber: '9', streetName: 'Morgan St', suburb: 'Timboon', state: 'VIC', postcode: '3268' })).toEqual('9 Morgan St, Timboon VIC 3268')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('from camel case', () => {
|
|
39
|
+
expect(fromCamelCase('testOneTwo')).toEqual('Test One Two')
|
|
40
|
+
expect(fromCamelCase('testOne Two')).toEqual('Test One Two')
|
|
41
|
+
expect(fromCamelCase('tesTOneTwo')).not.toEqual('Test One Two')
|
|
42
|
+
expect(fromCamelCase()).toBeUndefined()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('to camel case', () => {
|
|
46
|
+
expect(toCamelCase(undefined)).toBeUndefined()
|
|
47
|
+
expect(toCamelCase({ Test: 't' })).not.toEqual({ Test: 't' })
|
|
48
|
+
expect(toCamelCase({ Test: 't' })).toEqual({ test: 't' })
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('capitalize', () => {
|
|
52
|
+
expect(capitalizeWords('test')).toEqual('Test')
|
|
53
|
+
expect(capitalizeWords('test one')).toEqual('Test One')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('weekdays csv string sort value', () => {
|
|
57
|
+
expect(weekdayValue('sun, wed, sat')).toEqual(1)
|
|
58
|
+
expect(weekdayValue('wed, sat')).toEqual(4)
|
|
59
|
+
expect(weekdayValue('')).toEqual(8)
|
|
60
|
+
expect(weekdayValue()).toEqual(0)
|
|
61
|
+
expect(weekdayValue('sun, wed, sat, always')).toEqual(0)
|
|
62
|
+
expect(weekdayValue('Tuesday')).toEqual(3)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('weekday short name conversion', () => {
|
|
66
|
+
expect(weekdayShortName('Sun, Mon, tuesday')).toEqual('sun,mon,tue')
|
|
67
|
+
expect(weekdayShortName('Sun, Mon, blah')).toEqual('sun,mon')
|
|
68
|
+
expect(weekdayShortName('Sun, Fri, Wedne')).toEqual('sun,fri')
|
|
69
|
+
expect(weekdayShortName('Sunday')).toEqual('sun')
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
test('contains weekday', () => {
|
|
73
|
+
expect(containsWeekday('sun', 'sun')).toEqual(true)
|
|
74
|
+
expect(containsWeekday('sun', 'Sunday')).toEqual(true)
|
|
75
|
+
expect(containsWeekday('sun,mon,tue, wed', 'Tuesday')).toEqual(true)
|
|
76
|
+
expect(containsWeekday('sun,mon,tuesday, wed', 'Tuesday')).toEqual(true)
|
|
77
|
+
expect(containsWeekday('sun,mon, wed', 'tue')).toEqual(false)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('add weekday', () => {
|
|
81
|
+
expect(addWeekday(undefined, 'sun')).toEqual('sun')
|
|
82
|
+
expect(addWeekday(undefined, 'sun')).toEqual('sun')
|
|
83
|
+
expect(addWeekday('mon,sun', 'sun')).toEqual('sun,mon')
|
|
84
|
+
expect(addWeekday('mon,sun, always, m', 'sun')).toEqual('always,sun,mon')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('remove weekday', () => {
|
|
88
|
+
expect(removeWeekday(undefined, 'sun')).toEqual(undefined)
|
|
89
|
+
expect(removeWeekday('sun', 'sun')).toEqual(undefined)
|
|
90
|
+
expect(removeWeekday('sun, thur, tue', 'sun')).toEqual('tue,thu')
|
|
91
|
+
expect(removeWeekday('always', 'sun')).toEqual('always')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('is array of length', () => {
|
|
95
|
+
expect(isArrayOfLength([], 0)).toEqual(true)
|
|
96
|
+
expect(isArrayOfLength([1,1,1], 3)).toEqual(true)
|
|
97
|
+
expect(isArrayOfLength(undefined, 0)).toEqual(false)
|
|
98
|
+
expect(isArrayOfLength({}, 0)).toEqual(false)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('is lengthy array', () => {
|
|
102
|
+
expect(isLengthyArray([])).toEqual(false)
|
|
103
|
+
expect(isLengthyArray(undefined)).toEqual(false)
|
|
104
|
+
expect(isLengthyArray([1])).toEqual(true)
|
|
105
|
+
expect(isLengthyArray([1,1])).toEqual(true)
|
|
106
|
+
expect(isLengthyArray([1,1], 1)).toEqual(true)
|
|
107
|
+
expect(isLengthyArray([1,1], 3)).toEqual(false)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test('rounding decimal places', () => {
|
|
111
|
+
expect(roundTo(1, 0)).toEqual(1)
|
|
112
|
+
expect(roundTo(1.1, 0)).toEqual(1)
|
|
113
|
+
expect(roundTo(1.6, 0)).toEqual(2)
|
|
114
|
+
expect(roundTo(2.22567, 3)).toEqual(2.226)
|
|
115
|
+
expect(roundTo(2.22547, 3)).toEqual(2.225)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test('toggle csv', () => {
|
|
119
|
+
expect(toggleCSV('one,two,three', 'two')).toEqual('one,three')
|
|
120
|
+
expect(toggleCSV('two', 'two')).toEqual(null)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('csv contains', () => {
|
|
124
|
+
expect(csvContains('one,two,three', 'two')).toEqual(true)
|
|
125
|
+
expect(csvContains('one,two,three', 'three')).toEqual(true)
|
|
126
|
+
expect(csvContains('one,three', 'two')).toEqual(false)
|
|
127
|
+
expect(csvContains(undefined, 'two')).toEqual(false)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
test('copy deep', () => {
|
|
131
|
+
expect(copyDeep(null)).toStrictEqual(null)
|
|
132
|
+
expect(copyDeep(undefined)).toStrictEqual(undefined)
|
|
133
|
+
|
|
134
|
+
let item = { test: { one: 'treat' } }
|
|
135
|
+
let copy = copyDeep(item)
|
|
136
|
+
item.test.one = 'other'
|
|
137
|
+
|
|
138
|
+
expect(item.test).not.toEqual(copy.test)
|
|
139
|
+
expect(item).not.toEqual(copy)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('copy by property alphabet', () => {
|
|
143
|
+
expect(copyItemByAlphabet(null)).toStrictEqual(null)
|
|
144
|
+
expect(copyItemByAlphabet(undefined)).toStrictEqual(undefined)
|
|
145
|
+
|
|
146
|
+
let item = { test: { b: 'treat', a: 't' }, v: 'a', s: 'a', z: undefined }
|
|
147
|
+
//consistency
|
|
148
|
+
expect(JSON.stringify(copyItemByAlphabet(item))).toEqual(JSON.stringify(copyItemByAlphabet(item)))
|
|
149
|
+
expect(JSON.stringify(copyItemByAlphabet(item))).toEqual(JSON.stringify({ s: 'a', test: { a: 't', b: 'treat' }, v: 'a', z: undefined }))
|
|
150
|
+
expect(JSON.stringify(copyItemByAlphabet(item))).not.toEqual(JSON.stringify({ s: 'a', test: { b: 'treat', a: 't' }, v: 'a' }))
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('contains search', () => {
|
|
154
|
+
expect(containsSearch(undefined, undefined)).toEqual(true)
|
|
155
|
+
expect(containsSearch('a', undefined)).toEqual(true)
|
|
156
|
+
expect(containsSearch('aa', 'aa')).toEqual(true)
|
|
157
|
+
expect(containsSearch('aa', 'a')).toEqual(true)
|
|
158
|
+
expect(containsSearch('aa', 'b')).toEqual(false)
|
|
159
|
+
expect(containsSearch('Testing One Two Three', ' one')).toEqual(true)
|
|
160
|
+
expect(containsSearch('Testing One Two Three', ' one')).toEqual(false)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test('deep select', () => {
|
|
164
|
+
expect(deepSelect(null)).toEqual([])
|
|
165
|
+
|
|
166
|
+
let item = [
|
|
167
|
+
{ a: 'a', b: [{ a: 'd' }] },
|
|
168
|
+
{ a: 'b'},
|
|
169
|
+
{ a: 'c' }
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
expect(deepSelect(item, x => x.b).length).toEqual(4)
|
|
173
|
+
|
|
174
|
+
let ite = [{
|
|
175
|
+
b: [
|
|
176
|
+
{ a: 'a', b: [{ a: 'b', b: [{ a: 'c' }] }]},
|
|
177
|
+
{ a: 'd' },
|
|
178
|
+
{ a: 'e', b: [{ a: 'f' }]}
|
|
179
|
+
]
|
|
180
|
+
}]
|
|
181
|
+
|
|
182
|
+
expect(deepSelect(ite, x => x.b).length).toEqual(7)
|
|
183
|
+
|
|
184
|
+
let te = {
|
|
185
|
+
b: [
|
|
186
|
+
{ a: 'a', b: [{ a: 'b', b: [{ a: 'c' }] }]},
|
|
187
|
+
{ a: 'd' },
|
|
188
|
+
{ a: 'e', b: [{ a: 'f' }]}
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//misses the parent
|
|
193
|
+
expect(deepSelect(te, x => x.b).length).toEqual(6)
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
test('has search', () => {
|
|
197
|
+
expect(hasSearch(undefined, 'test', ['a', 'b'])).toEqual(false)
|
|
198
|
+
expect(hasSearch('test', undefined, ['a', 'b'])).toEqual(true)
|
|
199
|
+
expect(hasSearch({ test: 'one two three', a: 'one' }, 'four', ['test', 'a'])).toEqual(false)
|
|
200
|
+
expect(hasSearch({ test: 'two', a: 'one' }, 'one', undefined)).toEqual(false)
|
|
201
|
+
expect(hasSearch({ test: 'one two three', a: 'one', b: 'two' }, 'three', ['a', 'b'])).toEqual(false)
|
|
202
|
+
expect(hasSearch({ test: 'one two three', a: 'one', b: 'two' }, 'three', ['a', 'b', 'test'])).toEqual(true)
|
|
203
|
+
expect(hasSearch({ test: 'one two three', a: 'one', b: 'two' }, 'one', ['b'])).toEqual(false)
|
|
204
|
+
expect(hasSearch({ test: 'one two three', a: 'one', b: 'two' }, 'one', ['a', 'b'])).toEqual(true)
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
test('to compare string', () => {
|
|
208
|
+
expect(toCompareString('one')).toEqual('one')
|
|
209
|
+
expect(toCompareString(undefined)).toStrictEqual(null)
|
|
210
|
+
expect(toCompareString('one two three')).toEqual('onetwothree')
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test('nested value', () => {
|
|
214
|
+
let item = {
|
|
215
|
+
a: { b: 'b', c: { d: 'd' } },
|
|
216
|
+
b: 'str'
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
expect(nestedValue(item, 'b')).toEqual('str')
|
|
220
|
+
expect(nestedValue(item, 'a.c.d')).toEqual('d')
|
|
221
|
+
expect(nestedValue(item, 'a.b')).toEqual('b')
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
test('valid email', () => {
|
|
225
|
+
expect(validEmail('andrewderoon@gmail.com')).toEqual(true)
|
|
226
|
+
expect(validEmail('@gmail.com')).toEqual(false)
|
|
227
|
+
expect(validEmail('a@')).toEqual(false)
|
|
228
|
+
expect(validEmail('a@e')).toEqual(true)
|
|
229
|
+
expect(validEmail('andrewderoon.com')).toEqual(false)
|
|
230
|
+
})
|
|
231
|
+
})
|