@playpilot/tpi 3.3.3 → 3.4.0-beta.1

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.
Files changed (35) hide show
  1. package/dist/link-injections.js +8 -8
  2. package/package.json +1 -1
  3. package/src/lib/api.ts +6 -9
  4. package/src/lib/hash.ts +4 -0
  5. package/src/lib/linkInjection.ts +15 -40
  6. package/src/lib/localization.ts +7 -7
  7. package/src/lib/scss/_mixins.scss +0 -13
  8. package/src/lib/scss/global.scss +0 -5
  9. package/src/lib/scss/variables.scss +1 -1
  10. package/src/lib/session.ts +78 -0
  11. package/src/lib/tracking.ts +1 -2
  12. package/src/lib/types/injection.d.ts +2 -0
  13. package/src/lib/types/session.d.ts +14 -0
  14. package/src/routes/+page.svelte +37 -7
  15. package/src/routes/components/AfterArticlePlaylinks.svelte +6 -5
  16. package/src/routes/components/Editorial/Editor.svelte +36 -26
  17. package/src/routes/components/Editorial/Session.svelte +97 -0
  18. package/src/routes/components/Modal.svelte +1 -3
  19. package/src/routes/components/Playlinks.svelte +4 -5
  20. package/src/routes/components/Popover.svelte +1 -3
  21. package/src/routes/components/Title.svelte +0 -5
  22. package/src/tests/lib/api.test.js +14 -14
  23. package/src/tests/lib/linkInjection.test.js +56 -51
  24. package/src/tests/lib/localization.test.js +0 -7
  25. package/src/tests/lib/session.test.js +95 -0
  26. package/src/tests/lib/tracking.test.js +0 -16
  27. package/src/tests/routes/+page.test.js +14 -4
  28. package/src/tests/routes/components/Editorial/Editor.test.js +17 -1
  29. package/src/tests/routes/components/Editorial/EditorItem.test.js +7 -7
  30. package/src/tests/routes/components/Editorial/Session.test.js +80 -0
  31. package/src/tests/setup.js +23 -5
  32. package/src/lib/event.ts +0 -6
  33. package/src/lib/viewTransition.ts +0 -25
  34. package/src/tests/lib/event.test.js +0 -22
  35. package/src/tests/lib/viewTransition.test.js +0 -13
@@ -26,7 +26,7 @@ describe('EditorItem.svelte', () => {
26
26
  it('Should highlight and unhighlight the matching link when component is hovered', async () => {
27
27
  document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
28
28
 
29
- injectLinksInDocument(Array.from(document.querySelectorAll('p')), linkInjections)
29
+ injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
30
30
 
31
31
  const { getAllByText, container } = render(EditorItem, { linkInjection })
32
32
 
@@ -41,7 +41,7 @@ describe('EditorItem.svelte', () => {
41
41
  document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
42
42
 
43
43
  const linkInjectionWithAfterArticle = { ...linkInjection, in_text: true, after_article: true }
44
- injectLinksInDocument(Array.from(document.querySelectorAll('p')), { aiInjections: [linkInjectionWithAfterArticle], manualInjections: [] })
44
+ injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, { aiInjections: [linkInjectionWithAfterArticle], manualInjections: [] })
45
45
 
46
46
  const { container } = render(EditorItem, { linkInjection })
47
47
 
@@ -54,7 +54,7 @@ describe('EditorItem.svelte', () => {
54
54
 
55
55
  const failedInjection = generateInjection('This is a sentence', 'fail')
56
56
 
57
- injectLinksInDocument(Array.from(document.querySelectorAll('p')), { aiInjections: [], manualInjections: [failedInjection] })
57
+ injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, { aiInjections: [], manualInjections: [failedInjection] })
58
58
 
59
59
  const { container } = render(EditorItem, { linkInjection })
60
60
 
@@ -65,7 +65,7 @@ describe('EditorItem.svelte', () => {
65
65
  it('Should scroll matching link into view when component is clicked', async () => {
66
66
  document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
67
67
 
68
- injectLinksInDocument(Array.from(document.querySelectorAll('p')), linkInjections)
68
+ injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
69
69
 
70
70
  const { container } = render(EditorItem, { linkInjection })
71
71
 
@@ -76,7 +76,7 @@ describe('EditorItem.svelte', () => {
76
76
  it('Should not scroll matching link into view when component is clicked but there is no matching injection', async () => {
77
77
  document.body.innerHTML = '<main><p>This has no matching injections.</p></main>'
78
78
 
79
- injectLinksInDocument(Array.from(document.querySelectorAll('main p')), linkInjections)
79
+ injectLinksInDocument(Array.from(document.querySelectorAll('main p')), () => null, linkInjections)
80
80
 
81
81
  const { container } = render(EditorItem, { linkInjection })
82
82
 
@@ -87,7 +87,7 @@ describe('EditorItem.svelte', () => {
87
87
  it('Should not scroll matching link into view when component is clicked on button or input', async () => {
88
88
  document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
89
89
 
90
- injectLinksInDocument(Array.from(document.querySelectorAll('p')), linkInjections)
90
+ injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
91
91
 
92
92
  const { container } = render(EditorItem, { linkInjection })
93
93
 
@@ -101,7 +101,7 @@ describe('EditorItem.svelte', () => {
101
101
  it('Should highlight element in editor when hovering element on page', async () => {
102
102
  document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
103
103
 
104
- injectLinksInDocument(Array.from(document.querySelectorAll('p')), linkInjections)
104
+ injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
105
105
 
106
106
  await new Promise(res => setTimeout(res))
107
107
 
@@ -0,0 +1,80 @@
1
+ import { fireEvent, render, waitFor } from '@testing-library/svelte'
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
+
4
+ import Session from '../../../../routes/components/Editorial/Session.svelte'
5
+ import { fetchAsSession, isAllowedToEdit, saveCurrentSession } from '$lib/session'
6
+
7
+ // @ts-ignore
8
+ vi.mock(import('$lib/session'), async (importOriginal) => {
9
+ const actual = await importOriginal()
10
+ return {
11
+ ...actual,
12
+ fetchAsSession: vi.fn(() => {}),
13
+ saveCurrentSession: vi.fn(() => {}),
14
+ sessionPollPeriodMilliseconds: 500,
15
+ isAllowedToEdit: vi.fn(() => true),
16
+ }
17
+ })
18
+
19
+ describe('Session.svelte', () => {
20
+ const onallow = vi.fn()
21
+ const ondisallow = vi.fn()
22
+
23
+ beforeEach(() => {
24
+ vi.resetAllMocks()
25
+ })
26
+
27
+ it('Should call fetchAsSession on mount', () => {
28
+ render(Session)
29
+ expect(fetchAsSession).toHaveBeenCalled()
30
+ })
31
+
32
+ it('Should continously poll fetchAsSession', async () => {
33
+ render(Session)
34
+
35
+ await waitFor(() => expect(fetchAsSession).toHaveBeenCalledTimes(2))
36
+ await waitFor(() => expect(fetchAsSession).toHaveBeenCalledTimes(3))
37
+ await waitFor(() => expect(fetchAsSession).toHaveBeenCalledTimes(4))
38
+ })
39
+
40
+ it('Should not show alert and call given onallow function when user is allowed to edit', async () => {
41
+ vi.mocked(fetchAsSession).mockResolvedValueOnce({ automation_enabled: true, injections_enabled: true })
42
+ vi.mocked(isAllowedToEdit).mockReturnValueOnce(true)
43
+
44
+ const { queryByText } = render(Session, { onallow, ondisallow })
45
+
46
+ expect(queryByText('Someone else is currently editing this document.')).not.toBeTruthy()
47
+
48
+ await waitFor(() => {
49
+ expect(onallow).toHaveBeenCalled()
50
+ expect(ondisallow).not.toHaveBeenCalled()
51
+ })
52
+ })
53
+
54
+ it('Should show alert and call given ondisallow function if user is not allowed to edit', async () => {
55
+ vi.mocked(fetchAsSession).mockResolvedValueOnce({ automation_enabled: true, injections_enabled: true })
56
+ vi.mocked(isAllowedToEdit).mockReturnValueOnce(false)
57
+
58
+ const { getByText } = render(Session, { onallow, ondisallow })
59
+
60
+ await waitFor(() => {
61
+ expect(getByText('Someone else is currently editing this document.')).toBeTruthy()
62
+ expect(onallow).not.toHaveBeenCalled()
63
+ expect(ondisallow).toHaveBeenCalled()
64
+ })
65
+ })
66
+
67
+ it('Should call given ontakeover function when button is alert is clicked', async () => {
68
+ vi.mocked(fetchAsSession).mockResolvedValueOnce({ automation_enabled: true, injections_enabled: true })
69
+ vi.mocked(isAllowedToEdit).mockReturnValueOnce(false)
70
+
71
+ const ontakeover = vi.fn()
72
+ const { getByText } = render(Session, { onallow, ondisallow, ontakeover })
73
+
74
+ await waitFor(() => getByText('Take over editing'))
75
+ await fireEvent.click(getByText('Take over editing'))
76
+
77
+ expect(ontakeover).toHaveBeenCalled()
78
+ expect(saveCurrentSession).toHaveBeenCalled()
79
+ })
80
+ })
@@ -1,12 +1,9 @@
1
1
  import { cleanup } from '@testing-library/svelte'
2
2
  import { afterEach, beforeAll, beforeEach, vi } from 'vitest'
3
3
 
4
- vi.mock('svelte/transition')
5
-
6
4
  // https://github.com/jsdom/jsdom/issues/3429#issuecomment-1936128876
7
5
  const mockAnimations = () => {
8
6
  Element.prototype.animate ??= vi.fn().mockReturnValue({
9
- onfinish: null,
10
7
  finished: Promise.resolve(),
11
8
  cancel: vi.fn(),
12
9
  startTime: null,
@@ -35,8 +32,31 @@ const mockLocalStorage = () => {
35
32
  }
36
33
  }
37
34
 
35
+ const mockSessionStorage = () => {
36
+ /** @type {Record<string, string>} */
37
+ let store = {}
38
+
39
+ // @ts-ignore
40
+ ;(window).sessionStorage = {
41
+ getItem: function (key) {
42
+ return store[key] || null
43
+ },
44
+ setItem: function (key, value) {
45
+ store[key] = value.toString()
46
+ },
47
+ removeItem: function (key) {
48
+ delete store[key]
49
+ },
50
+ clear: function () {
51
+ store = {}
52
+ },
53
+ }
54
+ }
55
+
38
56
  beforeAll(() => {
57
+ mockAnimations()
39
58
  mockLocalStorage()
59
+ mockSessionStorage()
40
60
  })
41
61
 
42
62
  beforeEach(() => {
@@ -48,8 +68,6 @@ beforeEach(() => {
48
68
 
49
69
  window.HTMLElement.prototype.scrollIntoView = vi.fn()
50
70
  localStorage.clear()
51
-
52
- mockAnimations()
53
71
  })
54
72
 
55
73
  afterEach(() => {
package/src/lib/event.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Returns true when user performs event that should open a link in a new tab
3
- */
4
- export function isHoldingSpecialKey(event: MouseEvent) {
5
- return event.ctrlKey || event.metaKey || event.button !== 0
6
- }
@@ -1,25 +0,0 @@
1
- /**
2
- * Play a view transition if supported. We remove the view transition name from the old element and add it to the new.
3
- * If not support, simply call the callback.
4
- * A condition can be passed to optionally only call the callback without the view transition.
5
- */
6
- export function playFallbackViewTransition(callback: Function, condition: boolean): void {
7
- console.log(condition)
8
- if (!document.startViewTransition || !condition) {
9
- callback()
10
- return
11
- }
12
-
13
- document.startViewTransition(() => {
14
- const viewTransitionOldElement = document.querySelector('[data-view-transition-old]') as HTMLElement
15
- if (!viewTransitionOldElement) return
16
-
17
- const viewTransitionName = window.getComputedStyle(viewTransitionOldElement).getPropertyValue('view-transition-name')
18
- viewTransitionOldElement.style.viewTransitionName = 'none'
19
-
20
- callback()
21
-
22
- const viewTransitionNewElement = document.querySelector('[data-view-transition-new]') as HTMLElement
23
- if (viewTransitionNewElement) viewTransitionNewElement.style.viewTransitionName = viewTransitionName
24
- })
25
- }
@@ -1,22 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { isHoldingSpecialKey } from '$lib/event'
3
-
4
- describe('event.js', () => {
5
- describe('isHoldingSpecialKey', () => {
6
- it('Should return true when holding special key', () => {
7
- // @ts-ignore
8
- expect(isHoldingSpecialKey({ ctrlKey: true, button: 0 })).toBe(true)
9
- // @ts-ignore
10
- expect(isHoldingSpecialKey({ metaKey: true, button: 0 })).toBe(true)
11
- // @ts-ignore
12
- expect(isHoldingSpecialKey({ button: 1 })).toBe(true)
13
- })
14
-
15
- it('Should return false when not holding special kew', () => {
16
- // @ts-ignore
17
- expect(isHoldingSpecialKey({ ctrlKey: false, metaKey: false, button: 0 })).toBe(false)
18
- // @ts-ignore
19
- expect(isHoldingSpecialKey({ button: 0 })).toBe(false)
20
- })
21
- })
22
- })
@@ -1,13 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest'
2
- import { playFallbackViewTransition } from '$lib/viewTransition'
3
-
4
- describe('viewTransition.js', () => {
5
- describe('playFallbackViewTransition', () => {
6
- it('Should call callback', () => {
7
- const mock = vi.fn()
8
- playFallbackViewTransition(mock)
9
-
10
- expect(mock).toHaveBeenCalled()
11
- })
12
- })
13
- })