@playpilot/tpi 1.4.3 → 2.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/dist/link-injections.js +7 -7
- package/package.json +1 -1
- package/src/lib/api.js +13 -30
- package/src/lib/fakeData.js +2 -1
- package/src/lib/linkInjection.js +102 -11
- package/src/lib/text.js +0 -1
- package/src/routes/+layout.svelte +3 -1
- package/src/routes/+page.svelte +35 -16
- package/src/routes/components/Editorial/AIIndicator.svelte +133 -0
- package/src/routes/components/Editorial/Editor.svelte +39 -10
- package/src/routes/components/Editorial/EditorItem.svelte +2 -2
- package/src/routes/components/Editorial/ManualInjection.svelte +1 -0
- package/src/routes/components/Editorial/PlaylinkTypeSelect.svelte +2 -2
- package/src/routes/components/Icons/IconAi.svelte +1 -0
- package/src/tests/helpers.js +17 -0
- package/src/tests/lib/api.test.js +13 -26
- package/src/tests/lib/linkInjection.test.js +259 -250
- package/src/tests/routes/+page.test.js +16 -1
- package/src/tests/routes/components/Editorial/AiIndicator.test.js +58 -0
- package/src/tests/routes/components/Editorial/Editor.test.js +18 -20
- package/src/tests/routes/components/Editorial/EditorItem.test.js +12 -17
- package/src/tests/routes/components/Editorial/ManualInjection.test.js +12 -10
- package/src/typedefs.js +27 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render } from '@testing-library/svelte'
|
|
1
|
+
import { render, waitFor } from '@testing-library/svelte'
|
|
2
2
|
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
|
|
3
3
|
|
|
4
4
|
import page from '../../routes/+page.svelte'
|
|
@@ -43,6 +43,21 @@ describe('$routes/+page.svelte', () => {
|
|
|
43
43
|
expect(pollLinkInjections).toHaveBeenCalled()
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
+
it('Should call pollLinkInjections again if ai_running is true while in editorial mode', async () => {
|
|
47
|
+
vi.mocked(authorize).mockResolvedValueOnce(true)
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
window.PlayPilotLinkInjections = { editorial_token: 'some-token' }
|
|
50
|
+
|
|
51
|
+
vi.mocked(pollLinkInjections).mockResolvedValueOnce({ ai_running: true, injections_ready: true, page_updated: false, automation_enabled: true, injections_enabled: true, ai_injections: [], link_injections: [] })
|
|
52
|
+
|
|
53
|
+
render(page)
|
|
54
|
+
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(pollLinkInjections).toHaveBeenCalled()
|
|
57
|
+
expect(pollLinkInjections).toHaveBeenCalledTimes(2)
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
46
61
|
it('Should use the given selector when present', () => {
|
|
47
62
|
document.body.innerHTML = '<div class="some-element"><p>Here</p></div> <p>Not here</p>'
|
|
48
63
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { fireEvent, render, waitFor } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import AIIndicator from '../../../../routes/components/Editorial/AIIndicator.svelte'
|
|
5
|
+
import { generateInjection } from '../../../helpers'
|
|
6
|
+
|
|
7
|
+
describe('AIIndicator.svelte', () => {
|
|
8
|
+
it('Should should running state by default', () => {
|
|
9
|
+
const { getByText } = render(AIIndicator, { onadd: () => null })
|
|
10
|
+
|
|
11
|
+
expect(getByText('AI links are currently processing.', { exact: false })).toBeTruthy()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should show completed state with text depending on length of given array', async () => {
|
|
15
|
+
const { getByText, component } = render(AIIndicator, { onadd: () => null })
|
|
16
|
+
|
|
17
|
+
component.notifyUserOfNewState([generateInjection('Some sentence', 'Some title')])
|
|
18
|
+
await waitFor(() => {
|
|
19
|
+
expect(getByText('AI links are ready.', { exact: false })).toBeTruthy()
|
|
20
|
+
expect(getByText('1 New link was found.')).toBeTruthy()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
component.notifyUserOfNewState([generateInjection('Some sentence', 'Some title'), generateInjection('Some sentence', 'Some title')])
|
|
24
|
+
await waitFor(() => {
|
|
25
|
+
expect(getByText('AI links are ready.', { exact: false })).toBeTruthy()
|
|
26
|
+
expect(getByText('2 New links were found.')).toBeTruthy()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
component.notifyUserOfNewState([])
|
|
30
|
+
await waitFor(() => {
|
|
31
|
+
expect(getByText('AI links finished running, but no new links were found.')).toBeTruthy()
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('Should close element when dismiss button is clicked', async () => {
|
|
36
|
+
const { getByText, component, container } = render(AIIndicator, { onadd: () => null })
|
|
37
|
+
|
|
38
|
+
component.notifyUserOfNewState([])
|
|
39
|
+
await waitFor(() => getByText('Dismiss'))
|
|
40
|
+
|
|
41
|
+
await fireEvent.click(getByText('Dismiss'))
|
|
42
|
+
expect(container.querySelector('.ai-indicator')).not.toBeTruthy()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('Should close element and call onadd when Add AI links button is clicked', async () => {
|
|
46
|
+
const onadd = vi.fn()
|
|
47
|
+
const { getByText, component, container } = render(AIIndicator, { onadd })
|
|
48
|
+
|
|
49
|
+
const injection = generateInjection('Some sentence', 'Some title')
|
|
50
|
+
component.notifyUserOfNewState([injection])
|
|
51
|
+
await waitFor(() => getByText('Add AI links'))
|
|
52
|
+
|
|
53
|
+
await fireEvent.click(getByText('Add AI links'))
|
|
54
|
+
|
|
55
|
+
expect(onadd).toHaveBeenCalledWith([injection])
|
|
56
|
+
expect(container.querySelector('.ai-indicator')).not.toBeTruthy()
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -1,29 +1,19 @@
|
|
|
1
|
-
import { render } from '@testing-library/svelte'
|
|
1
|
+
import { fireEvent, render } from '@testing-library/svelte'
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest'
|
|
3
3
|
|
|
4
4
|
import Editor from '../../../../routes/components/Editorial/Editor.svelte'
|
|
5
5
|
import { title } from '$lib/fakeData'
|
|
6
|
+
import { generateInjection } from '../../../helpers'
|
|
6
7
|
|
|
7
8
|
vi.mock('$lib/api', () => ({
|
|
8
9
|
saveLinkInjections: vi.fn(),
|
|
9
10
|
}))
|
|
10
11
|
|
|
11
12
|
describe('Editor.svelte', () => {
|
|
12
|
-
const linkInjections = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
sentence: 'This is a sentence with an injection.',
|
|
17
|
-
playpilot_url: 'https://some-link.com/',
|
|
18
|
-
title_details: title,
|
|
19
|
-
}, {
|
|
20
|
-
sid: '456',
|
|
21
|
-
key: '2',
|
|
22
|
-
title: 'a sentence',
|
|
23
|
-
sentence: 'This is a sentence with an injection.',
|
|
24
|
-
playpilot_url: 'https://some-link.com/',
|
|
25
|
-
title_details: title,
|
|
26
|
-
}]
|
|
13
|
+
const linkInjections = [
|
|
14
|
+
generateInjection('This is a sentence with an injection.', 'an injection'),
|
|
15
|
+
generateInjection('This is a sentence with an injection.', 'a sentence'),
|
|
16
|
+
]
|
|
27
17
|
|
|
28
18
|
it('Should show the number of injections', () => {
|
|
29
19
|
const { getByText } = render(Editor, { linkInjections })
|
|
@@ -56,15 +46,23 @@ describe('Editor.svelte', () => {
|
|
|
56
46
|
expect(queryByText('Save links')).not.toBeTruthy()
|
|
57
47
|
})
|
|
58
48
|
|
|
59
|
-
it('Should show save button if injections are present', async () => {
|
|
49
|
+
it('Should not show save button if injections are present but no change is made', async () => {
|
|
60
50
|
const { queryByText } = render(Editor, { linkInjections, loading: false })
|
|
61
51
|
|
|
62
|
-
expect(queryByText('Save links')).toBeTruthy()
|
|
52
|
+
expect(queryByText('Save links')).not.toBeTruthy()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('Should show save button if injections are present and a change has been made', async () => {
|
|
56
|
+
const { getByText, getAllByText } = render(Editor, { linkInjections, loading: false })
|
|
57
|
+
|
|
58
|
+
await fireEvent.click(getAllByText('Visible')[0])
|
|
59
|
+
|
|
60
|
+
expect(getByText('Save links')).toBeTruthy()
|
|
63
61
|
})
|
|
64
62
|
|
|
65
63
|
it('Should show empty state if no links are found', async () => {
|
|
66
|
-
const {
|
|
64
|
+
const { getByText } = render(Editor, { linkInjections: [], loading: false })
|
|
67
65
|
|
|
68
|
-
expect(
|
|
66
|
+
expect(getByText('No links available', { exact: false })).toBeTruthy()
|
|
69
67
|
})
|
|
70
68
|
})
|
|
@@ -3,34 +3,29 @@ import { describe, expect, it, vi } from 'vitest'
|
|
|
3
3
|
|
|
4
4
|
import EditorItem from '../../../../routes/components/Editorial/EditorItem.svelte'
|
|
5
5
|
import { injectLinksInDocument } from '$lib/linkInjection'
|
|
6
|
-
import { title } from '$lib/fakeData'
|
|
6
|
+
import { linkInjections, title } from '$lib/fakeData'
|
|
7
7
|
import { track } from '$lib/tracking'
|
|
8
|
+
import { generateInjection } from '../../../helpers'
|
|
8
9
|
|
|
9
10
|
vi.mock('$lib/tracking', () => ({
|
|
10
11
|
track: vi.fn(),
|
|
11
12
|
}))
|
|
12
13
|
|
|
13
14
|
describe('EditorItem.svelte', () => {
|
|
14
|
-
const linkInjection =
|
|
15
|
-
|
|
16
|
-
title: 'an injection',
|
|
17
|
-
sentence: 'This is a sentence with an injection.',
|
|
18
|
-
playpilot_url: 'https://some-link.com/',
|
|
19
|
-
key: 'some-key',
|
|
20
|
-
title_details: title,
|
|
21
|
-
}
|
|
15
|
+
const linkInjection = generateInjection('This is a sentence with an injection.', 'an injection')
|
|
16
|
+
const linkInjections = { aiInjections: [linkInjection], manualInjections: [] }
|
|
22
17
|
|
|
23
18
|
it('Should render the given title', () => {
|
|
24
19
|
const { getByText, getByRole } = render(EditorItem, { linkInjection })
|
|
25
20
|
|
|
26
|
-
expect(getByText(linkInjection.title_details
|
|
27
|
-
expect(/** @type {HTMLImageElement} */ (getByRole('presentation')).src).toContain(linkInjection.title_details
|
|
21
|
+
expect(getByText(linkInjection.title_details?.title || '')).toBeTruthy()
|
|
22
|
+
expect(/** @type {HTMLImageElement} */ (getByRole('presentation')).src).toContain(linkInjection.title_details?.standing_poster)
|
|
28
23
|
})
|
|
29
24
|
|
|
30
25
|
it('Should highlight and unhighlight the matching link when component is hovered', async () => {
|
|
31
26
|
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
32
27
|
|
|
33
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')),
|
|
28
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
|
|
34
29
|
|
|
35
30
|
const { getAllByText, container } = render(EditorItem, { linkInjection })
|
|
36
31
|
|
|
@@ -45,7 +40,7 @@ describe('EditorItem.svelte', () => {
|
|
|
45
40
|
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
46
41
|
|
|
47
42
|
const linkInjectionWithAfterArticle = { ...linkInjection, in_text: true, after_article: true }
|
|
48
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')), [linkInjectionWithAfterArticle],
|
|
43
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, { aiInjections: [linkInjectionWithAfterArticle], manualInjections: [] })
|
|
49
44
|
|
|
50
45
|
const { container } = render(EditorItem, { linkInjection })
|
|
51
46
|
|
|
@@ -56,7 +51,7 @@ describe('EditorItem.svelte', () => {
|
|
|
56
51
|
it('Should scroll matching link into view when component is clicked', async () => {
|
|
57
52
|
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
58
53
|
|
|
59
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')),
|
|
54
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
|
|
60
55
|
|
|
61
56
|
const { container } = render(EditorItem, { linkInjection })
|
|
62
57
|
|
|
@@ -67,7 +62,7 @@ describe('EditorItem.svelte', () => {
|
|
|
67
62
|
it('Should not scroll matching link into view when component is clicked but there is no matching injection', async () => {
|
|
68
63
|
document.body.innerHTML = '<p>This has no matching injections.</p>'
|
|
69
64
|
|
|
70
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')),
|
|
65
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
|
|
71
66
|
|
|
72
67
|
const { container } = render(EditorItem, { linkInjection })
|
|
73
68
|
|
|
@@ -78,7 +73,7 @@ describe('EditorItem.svelte', () => {
|
|
|
78
73
|
it('Should not scroll matching link into view when component is clicked on button or input', async () => {
|
|
79
74
|
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
80
75
|
|
|
81
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')),
|
|
76
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
|
|
82
77
|
|
|
83
78
|
const { container } = render(EditorItem, { linkInjection })
|
|
84
79
|
|
|
@@ -92,7 +87,7 @@ describe('EditorItem.svelte', () => {
|
|
|
92
87
|
it('Should highlight element in editor when hovering element on page', async () => {
|
|
93
88
|
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
94
89
|
|
|
95
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')),
|
|
90
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
|
|
96
91
|
|
|
97
92
|
await new Promise(res => setTimeout(res))
|
|
98
93
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { fireEvent, render, waitFor } from '@testing-library/svelte'
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import ManualInjection from '../../../../routes/components/Editorial/ManualInjection.svelte'
|
|
5
5
|
import { searchTitles } from '$lib/search'
|
|
6
6
|
import { title } from '$lib/fakeData'
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ vi.mock('$lib/search', () => ({
|
|
|
9
9
|
searchTitles: vi.fn(),
|
|
10
10
|
}))
|
|
11
11
|
|
|
12
|
-
describe('
|
|
12
|
+
describe('ManualInjection.svelte', () => {
|
|
13
13
|
beforeEach(() => {
|
|
14
14
|
vi.resetAllMocks()
|
|
15
15
|
|
|
@@ -31,7 +31,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
it('Should input selected text in selected text input and search input', async () => {
|
|
34
|
-
const { getByLabelText } = render(
|
|
34
|
+
const { getByLabelText } = render(ManualInjection, { htmlString: document.body.innerHTML, onsave: () => null })
|
|
35
35
|
|
|
36
36
|
await fireEvent.click(window)
|
|
37
37
|
|
|
@@ -41,15 +41,15 @@ describe('TitleSearch.svelte', () => {
|
|
|
41
41
|
})
|
|
42
42
|
|
|
43
43
|
it('Should disable save button by default', async () => {
|
|
44
|
-
const { getByText } = render(
|
|
44
|
+
const { getByText } = render(ManualInjection, { htmlString: '', onsave: () => null })
|
|
45
45
|
|
|
46
46
|
expect(getByText('Add playlink').hasAttribute('disabled')).toBeTruthy()
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
it('Should enable save button after selecting text and selecting title from
|
|
49
|
+
it('Should enable save button after selecting text and selecting title from ManualInjection', async () => {
|
|
50
50
|
vi.mocked(searchTitles).mockResolvedValueOnce([title])
|
|
51
51
|
|
|
52
|
-
const { getByText } = render(
|
|
52
|
+
const { getByText } = render(ManualInjection, { htmlString: document.body.innerHTML, onsave: () => null })
|
|
53
53
|
|
|
54
54
|
await fireEvent.click(window)
|
|
55
55
|
await waitFor(() => getByText(title.title))
|
|
@@ -62,7 +62,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
62
62
|
vi.mocked(searchTitles).mockResolvedValueOnce([title])
|
|
63
63
|
|
|
64
64
|
const onsave = vi.fn()
|
|
65
|
-
const { getByText } = render(
|
|
65
|
+
const { getByText } = render(ManualInjection, { htmlString: document.body.innerHTML, onsave })
|
|
66
66
|
|
|
67
67
|
await fireEvent.click(window)
|
|
68
68
|
await fireEvent.click(getByText(title.title))
|
|
@@ -75,6 +75,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
75
75
|
playpilot_url: `https://www.playpilot.com/show/${title.slug}`,
|
|
76
76
|
key: expect.any(String),
|
|
77
77
|
title_details: title,
|
|
78
|
+
manual: true,
|
|
78
79
|
})
|
|
79
80
|
})
|
|
80
81
|
|
|
@@ -98,7 +99,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
98
99
|
}))
|
|
99
100
|
|
|
100
101
|
const onsave = vi.fn()
|
|
101
|
-
const { getByText } = render(
|
|
102
|
+
const { getByText } = render(ManualInjection, { htmlString: document.body.innerHTML, onsave })
|
|
102
103
|
|
|
103
104
|
await fireEvent.click(window)
|
|
104
105
|
await fireEvent.click(getByText(title.title))
|
|
@@ -111,6 +112,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
111
112
|
playpilot_url: `https://www.playpilot.com/show/${title.slug}`,
|
|
112
113
|
key: expect.any(String),
|
|
113
114
|
title_details: title,
|
|
115
|
+
manual: true,
|
|
114
116
|
})
|
|
115
117
|
})
|
|
116
118
|
|
|
@@ -122,7 +124,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
122
124
|
let container = document.querySelector('div')
|
|
123
125
|
|
|
124
126
|
const onsave = vi.fn()
|
|
125
|
-
const { unmount } = render(
|
|
127
|
+
const { unmount } = render(ManualInjection, { htmlString: document.body.innerHTML, onsave })
|
|
126
128
|
|
|
127
129
|
// @ts-ignore
|
|
128
130
|
window.getSelection = vi.fn(() => ({
|
|
@@ -156,7 +158,7 @@ describe('TitleSearch.svelte', () => {
|
|
|
156
158
|
anchorNode: container,
|
|
157
159
|
}))
|
|
158
160
|
|
|
159
|
-
;(render(
|
|
161
|
+
;(render(ManualInjection, { htmlString: document.body.innerHTML, onsave }))
|
|
160
162
|
|
|
161
163
|
await fireEvent.click(window)
|
|
162
164
|
|
package/src/typedefs.js
CHANGED
|
@@ -43,17 +43,20 @@
|
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* @typedef {{
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
46
|
+
* sid: string,
|
|
47
|
+
* title: string,
|
|
48
|
+
* sentence: string,
|
|
49
|
+
* playpilot_url: string,
|
|
50
|
+
* key: string,
|
|
51
|
+
* title_details?: TitleData,
|
|
52
|
+
* inactive?: boolean,
|
|
53
|
+
* failed?: boolean,
|
|
54
|
+
* in_text?: boolean,
|
|
55
|
+
* after_article?: boolean,
|
|
56
|
+
* after_article_style?: 'modal_button' | 'playlinks' | null,
|
|
57
|
+
* manual?: boolean,
|
|
58
|
+
* removed?: boolean,
|
|
59
|
+
* duplicate?: boolean,
|
|
57
60
|
* }} LinkInjection
|
|
58
61
|
*/
|
|
59
62
|
|
|
@@ -64,7 +67,19 @@
|
|
|
64
67
|
*/
|
|
65
68
|
|
|
66
69
|
/**
|
|
67
|
-
* @typedef {{
|
|
70
|
+
* @typedef {{
|
|
71
|
+
* injections_ready: boolean,
|
|
72
|
+
* page_updated: boolean,
|
|
73
|
+
* automation_enabled: boolean,
|
|
74
|
+
* injections_enabled: boolean,
|
|
75
|
+
* ai_running: boolean,
|
|
76
|
+
* ai_injections: LinkInjection[] | null,
|
|
77
|
+
* link_injections: LinkInjection[] | null,
|
|
78
|
+
* }} LinkInjectionResponse
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {{ aiInjections: LinkInjection[], manualInjections: LinkInjection[] }} LinkInjectionTypes
|
|
68
83
|
*/
|
|
69
84
|
|
|
70
85
|
/**
|