@playpilot/tpi 3.1.0 → 3.2.0-beta.2
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 +8 -7
- package/package.json +1 -1
- package/src/lib/actions/heading.ts +11 -0
- package/src/lib/api.ts +1 -3
- package/src/lib/auth.ts +13 -1
- package/src/lib/constants.ts +2 -0
- package/src/lib/enums/TrackingEvent.ts +1 -0
- package/src/lib/linkInjection.ts +43 -32
- package/src/lib/scss/_mixins.scss +8 -0
- package/src/lib/scss/global.scss +6 -6
- package/src/lib/scss/variables.scss +2 -0
- package/src/lib/stores/organization.ts +4 -0
- package/src/lib/tracking.ts +14 -1
- package/src/lib/types/injection.d.ts +5 -0
- package/src/routes/+layout.svelte +6 -2
- package/src/routes/+page.svelte +31 -13
- package/src/routes/components/Description.svelte +2 -3
- package/src/routes/components/Editorial/AIIndicator.svelte +85 -91
- package/src/routes/components/Editorial/Alert.svelte +12 -2
- package/src/routes/components/Editorial/Editor.svelte +82 -61
- package/src/routes/components/Editorial/EditorItem.svelte +32 -7
- package/src/routes/components/Editorial/ManualInjection.svelte +10 -9
- package/src/routes/components/Editorial/PlaylinkTypeSelect.svelte +14 -0
- package/src/routes/components/Editorial/ResizeHandle.svelte +1 -1
- package/src/routes/components/Editorial/Search/TitleSearchItem.svelte +7 -5
- package/src/routes/components/Icons/IconWarning.svelte +5 -0
- package/src/routes/components/Modal.svelte +2 -0
- package/src/routes/components/Playlinks.svelte +12 -11
- package/src/routes/components/Popover.svelte +2 -0
- package/src/routes/components/Title.svelte +3 -2
- package/src/routes/components/TitlePopover.svelte +1 -1
- package/src/tests/lib/auth.test.js +31 -1
- package/src/tests/lib/linkInjection.test.js +87 -48
- package/src/tests/lib/tracking.test.js +61 -1
- package/src/tests/routes/+page.test.js +94 -4
- package/src/tests/routes/components/Editorial/AiIndicator.test.js +28 -42
- package/src/tests/routes/components/Editorial/Alert.test.js +10 -3
- package/src/tests/routes/components/Editorial/Editor.test.js +15 -0
- package/src/tests/routes/components/Editorial/EditorItem.test.js +32 -7
- package/src/tests/routes/components/Editorial/PlaylinkTypeSelect.test.js +13 -1
- package/src/tests/routes/components/Title.test.js +2 -2
- package/svelte.config.js +1 -0
|
@@ -1,61 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { describe, expect, it
|
|
1
|
+
import { render } from '@testing-library/svelte'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
3
|
|
|
4
4
|
import AIIndicator from '../../../../routes/components/Editorial/AIIndicator.svelte'
|
|
5
|
-
import { generateInjection } from '../../../helpers'
|
|
6
5
|
|
|
7
6
|
describe('AIIndicator.svelte', () => {
|
|
8
|
-
it('Should
|
|
9
|
-
const { getByText,
|
|
7
|
+
it('Should show disabled state by default', () => {
|
|
8
|
+
const { getByText, queryByTestId } = render(AIIndicator)
|
|
9
|
+
|
|
10
|
+
expect(getByText('AI processing is disabled', { exact: false })).toBeTruthy()
|
|
11
|
+
expect(queryByTestId('loading-bar')).not.toBeTruthy()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should show running when aiRunning and automationEnabled are true', () => {
|
|
15
|
+
const { getByText, getByTestId } = render(AIIndicator, { aiRunning: true, automationEnabled: true })
|
|
10
16
|
|
|
11
17
|
expect(getByText('AI links are currently processing.', { exact: false })).toBeTruthy()
|
|
12
18
|
expect(getByTestId('loading-bar')).toBeTruthy()
|
|
13
19
|
})
|
|
14
20
|
|
|
15
|
-
it('Should show
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
component.notifyUserOfNewState([generateInjection('Some sentence', 'Some title')])
|
|
19
|
-
await waitFor(() => {
|
|
20
|
-
expect(getByText('AI links are ready.', { exact: false })).toBeTruthy()
|
|
21
|
-
expect(getByText('1 New link was found.')).toBeTruthy()
|
|
22
|
-
expect(queryByTestId('loading-bar')).not.toBeTruthy()
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
component.notifyUserOfNewState([generateInjection('Some sentence', 'Some title'), generateInjection('Some sentence', 'Some title')])
|
|
26
|
-
await waitFor(() => {
|
|
27
|
-
expect(getByText('AI links are ready.', { exact: false })).toBeTruthy()
|
|
28
|
-
expect(getByText('2 New links were found.')).toBeTruthy()
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
component.notifyUserOfNewState([])
|
|
32
|
-
await waitFor(() => {
|
|
33
|
-
expect(getByText('AI links finished running, but no new links were found.')).toBeTruthy()
|
|
34
|
-
expect(queryByTestId('loading-bar')).not.toBeTruthy()
|
|
35
|
-
})
|
|
36
|
-
})
|
|
21
|
+
it('Should not show animator or loading bar if aiRunning is false', () => {
|
|
22
|
+
const { queryByTestId } = render(AIIndicator, { aiRunning: false })
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
expect(queryByTestId('loading-bar')).not.toBeTruthy()
|
|
25
|
+
expect(queryByTestId('animator')).not.toBeTruthy()
|
|
26
|
+
})
|
|
40
27
|
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
it('Should show given message if aiRunning is true', () => {
|
|
29
|
+
const { getByText } = render(AIIndicator, { aiRunning: true, automationEnabled: true, message: 'Some message' })
|
|
43
30
|
|
|
44
|
-
|
|
45
|
-
expect(container.querySelector('.ai-indicator')).not.toBeTruthy()
|
|
31
|
+
expect(getByText('Some message')).toBeTruthy()
|
|
46
32
|
})
|
|
47
33
|
|
|
48
|
-
it('Should
|
|
49
|
-
const
|
|
50
|
-
const { getByText, component, container } = render(AIIndicator, { onadd })
|
|
34
|
+
it('Should set progress bar to given progress percentage', () => {
|
|
35
|
+
const { getByText, getByTestId } = render(AIIndicator, { aiRunning: true, automationEnabled: true, percentage: 25 })
|
|
51
36
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
37
|
+
expect(getByTestId('loading-bar').style.width).toBe('25%')
|
|
38
|
+
expect(getByText('25%')).toBeTruthy()
|
|
39
|
+
})
|
|
55
40
|
|
|
56
|
-
|
|
41
|
+
it('Should limit progress to minimum value in loading bar style only', () => {
|
|
42
|
+
const { getByText, getByTestId } = render(AIIndicator, { aiRunning: true, automationEnabled: true, percentage: 0 })
|
|
57
43
|
|
|
58
|
-
expect(
|
|
59
|
-
expect(
|
|
44
|
+
expect(getByTestId('loading-bar').style.width).toBe('3%')
|
|
45
|
+
expect(getByText('0%')).toBeTruthy()
|
|
60
46
|
})
|
|
61
47
|
})
|
|
@@ -5,13 +5,20 @@ import Alert from '../../../../routes/components/Editorial/Alert.svelte'
|
|
|
5
5
|
import { createRawSnippet } from 'svelte'
|
|
6
6
|
|
|
7
7
|
describe('Alert.svelte', () => {
|
|
8
|
+
const children = createRawSnippet(() => ({
|
|
9
|
+
render: () => '<p>Some snippet</p>',
|
|
10
|
+
}))
|
|
11
|
+
|
|
8
12
|
it('Should render the given snippet', () => {
|
|
9
|
-
const children = createRawSnippet(() => ({
|
|
10
|
-
render: () => '<p>Some snippet</p>',
|
|
11
|
-
}))
|
|
12
13
|
|
|
13
14
|
const { getByText } = render(Alert, { children })
|
|
14
15
|
|
|
15
16
|
expect(getByText('Some snippet')).toBeTruthy()
|
|
16
17
|
})
|
|
18
|
+
|
|
19
|
+
it('Should render with given type as class', () => {
|
|
20
|
+
const { container } = render(Alert, { children, type: 'warning' })
|
|
21
|
+
|
|
22
|
+
expect(container.querySelector('.alert')?.classList).toContain('warning')
|
|
23
|
+
})
|
|
17
24
|
})
|
|
@@ -89,18 +89,21 @@ describe('Editor.svelte', () => {
|
|
|
89
89
|
it('Should not show save button if no injections are present', async () => {
|
|
90
90
|
const { queryByText } = render(Editor, { linkInjections: [], loading: false })
|
|
91
91
|
|
|
92
|
+
await new Promise(res => setTimeout(res))
|
|
92
93
|
expect(queryByText('Save links')).not.toBeTruthy()
|
|
93
94
|
})
|
|
94
95
|
|
|
95
96
|
it('Should not show save button if injections are present but no change is made', async () => {
|
|
96
97
|
const { queryByText } = render(Editor, { linkInjections, loading: false })
|
|
97
98
|
|
|
99
|
+
await new Promise(res => setTimeout(res))
|
|
98
100
|
expect(queryByText('Save links')).not.toBeTruthy()
|
|
99
101
|
})
|
|
100
102
|
|
|
101
103
|
it('Should show save button if injections are present and a change has been made', async () => {
|
|
102
104
|
const { getByText, getAllByText } = render(Editor, { linkInjections, loading: false })
|
|
103
105
|
|
|
106
|
+
await new Promise(res => setTimeout(res))
|
|
104
107
|
await fireEvent.click(getAllByText('Visible')[0])
|
|
105
108
|
|
|
106
109
|
expect(getByText('Save links')).toBeTruthy()
|
|
@@ -112,6 +115,18 @@ describe('Editor.svelte', () => {
|
|
|
112
115
|
expect(getByText('No links available', { exact: false })).toBeTruthy()
|
|
113
116
|
})
|
|
114
117
|
|
|
118
|
+
it('Should show message if injections are not enabled', async () => {
|
|
119
|
+
const { getByText } = render(Editor, { linkInjections: [], loading: false, injectionsEnabled: false })
|
|
120
|
+
|
|
121
|
+
expect(getByText('Playlinks are currently not published.')).toBeTruthy()
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('Should not show message if injections are enabled', async () => {
|
|
125
|
+
const { queryByText } = render(Editor, { linkInjections: [], loading: false, injectionsEnabled: true })
|
|
126
|
+
|
|
127
|
+
expect(queryByText('Playlinks are currently not published.')).not.toBeTruthy()
|
|
128
|
+
})
|
|
129
|
+
|
|
115
130
|
it('Should sort injections based on their named and .failed state', () => {
|
|
116
131
|
const linkInjections = [
|
|
117
132
|
{ ...generateInjection('Sentence', 'c'), manual: true, title_details: { ...title, title: 'c' } },
|
|
@@ -29,10 +29,10 @@ describe('EditorItem.svelte', () => {
|
|
|
29
29
|
const { getAllByText, container } = render(EditorItem, { linkInjection })
|
|
30
30
|
|
|
31
31
|
await fireEvent.mouseEnter(/** @type {HTMLElement} */ (container.querySelector('.item')))
|
|
32
|
-
expect(/** @type {HTMLElement} */ (getAllByText(linkInjection.title)[0].closest('span')).classList).toContain('injection-highlight')
|
|
32
|
+
expect(/** @type {HTMLElement} */ (getAllByText(linkInjection.title)[0].closest('span')).classList).toContain('playpilot-injection-highlight')
|
|
33
33
|
|
|
34
34
|
await fireEvent.mouseLeave(/** @type {HTMLElement} */ (container.querySelector('.item')))
|
|
35
|
-
expect(/** @type {HTMLElement} */ (getAllByText(linkInjection.title)[0].closest('span')).classList).not.toContain('injection-highlight')
|
|
35
|
+
expect(/** @type {HTMLElement} */ (getAllByText(linkInjection.title)[0].closest('span')).classList).not.toContain('playpilot-injection-highlight')
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
it('Should highlight multiple elements if multiple are present', async () => {
|
|
@@ -44,7 +44,20 @@ describe('EditorItem.svelte', () => {
|
|
|
44
44
|
const { container } = render(EditorItem, { linkInjection })
|
|
45
45
|
|
|
46
46
|
await fireEvent.mouseEnter(/** @type {HTMLElement} */ (container.querySelector('.item')))
|
|
47
|
-
expect(document.querySelectorAll('.injection-highlight')).toHaveLength(2)
|
|
47
|
+
expect(document.querySelectorAll('.playpilot-injection-highlight')).toHaveLength(2)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('Should highlight the sentence the injection is in if an injection failed but a matching sentence exists.', async () => {
|
|
51
|
+
document.body.innerHTML = '<p>This is a sentence with an injection.</p>'
|
|
52
|
+
|
|
53
|
+
const failedInjection = generateInjection('This is a sentence', 'fail')
|
|
54
|
+
|
|
55
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, { aiInjections: [], manualInjections: [failedInjection] })
|
|
56
|
+
|
|
57
|
+
const { container } = render(EditorItem, { linkInjection })
|
|
58
|
+
|
|
59
|
+
await fireEvent.mouseEnter(/** @type {HTMLElement} */ (container.querySelector('.item')))
|
|
60
|
+
expect(/** @type {HTMLElement} */ (document.querySelector('p')).classList).toContain('playpilot-injection-highlight')
|
|
48
61
|
})
|
|
49
62
|
|
|
50
63
|
it('Should scroll matching link into view when component is clicked', async () => {
|
|
@@ -59,9 +72,9 @@ describe('EditorItem.svelte', () => {
|
|
|
59
72
|
})
|
|
60
73
|
|
|
61
74
|
it('Should not scroll matching link into view when component is clicked but there is no matching injection', async () => {
|
|
62
|
-
document.body.innerHTML = '<p>This has no matching injections.</p>'
|
|
75
|
+
document.body.innerHTML = '<main><p>This has no matching injections.</p></main>'
|
|
63
76
|
|
|
64
|
-
injectLinksInDocument(Array.from(document.querySelectorAll('p')), () => null, linkInjections)
|
|
77
|
+
injectLinksInDocument(Array.from(document.querySelectorAll('main p')), () => null, linkInjections)
|
|
65
78
|
|
|
66
79
|
const { container } = render(EditorItem, { linkInjection })
|
|
67
80
|
|
|
@@ -108,9 +121,9 @@ describe('EditorItem.svelte', () => {
|
|
|
108
121
|
})
|
|
109
122
|
|
|
110
123
|
it('Should show different state when injection failed', () => {
|
|
111
|
-
const { getByText, queryByLabelText } = render(EditorItem, { linkInjection: { ...linkInjection, failed: true } })
|
|
124
|
+
const { getByText, queryByLabelText } = render(EditorItem, { linkInjection: { ...linkInjection, failed: true, failed_message: 'Some message' } })
|
|
112
125
|
|
|
113
|
-
expect(getByText('
|
|
126
|
+
expect(getByText('Some message')).toBeTruthy()
|
|
114
127
|
expect(queryByLabelText('Expand')).not.toBeTruthy()
|
|
115
128
|
expect(track).toHaveBeenCalled()
|
|
116
129
|
})
|
|
@@ -164,4 +177,16 @@ describe('EditorItem.svelte', () => {
|
|
|
164
177
|
expect(queryByText('Visible')).toBeTruthy()
|
|
165
178
|
expect(container.querySelector('.inactive')).not.toBeTruthy()
|
|
166
179
|
})
|
|
180
|
+
|
|
181
|
+
it('Should display an icon when playlink types are invalid', async () => {
|
|
182
|
+
const { getByLabelText } = render(EditorItem, { linkInjection: { ...linkInjection, in_text: false } })
|
|
183
|
+
|
|
184
|
+
expect(getByLabelText('Invalid playlink settings')).toBeTruthy()
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('Should not display an icon when playlink types are valid', async () => {
|
|
188
|
+
const { queryByLabelText } = render(EditorItem, { linkInjection: { ...linkInjection, in_text: true } })
|
|
189
|
+
|
|
190
|
+
expect(queryByLabelText('Invalid playlink settings')).not.toBeTruthy()
|
|
191
|
+
})
|
|
167
192
|
})
|
|
@@ -4,7 +4,7 @@ import { beforeEach, describe, expect, it } from 'vitest'
|
|
|
4
4
|
import PlaylinkTypeSelect from '../../../../routes/components/Editorial/PlaylinkTypeSelect.svelte'
|
|
5
5
|
|
|
6
6
|
describe('PlaylinkTypeSelect.svelte', () => {
|
|
7
|
-
/** @type {LinkInjection} */
|
|
7
|
+
/** @type {import('$lib/types/injection').LinkInjection} */
|
|
8
8
|
const linkInjection = {
|
|
9
9
|
sid: '1',
|
|
10
10
|
title: 'test',
|
|
@@ -60,4 +60,16 @@ describe('PlaylinkTypeSelect.svelte', () => {
|
|
|
60
60
|
expect(getByText('Modal button').classList).toContain('active')
|
|
61
61
|
expect(/** @type {HTMLElement} */(document.querySelector('.active-marker')).classList).toContain('right')
|
|
62
62
|
})
|
|
63
|
+
|
|
64
|
+
it('Should display a message when playlink types are invalid', async () => {
|
|
65
|
+
const { getByText } = render(PlaylinkTypeSelect, { linkInjection: { ...linkInjection, in_text: false } })
|
|
66
|
+
|
|
67
|
+
expect(getByText('At least one layout option must be selected for the playlink to be visible.')).toBeTruthy()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('Should not display a message when playlink types are valid', async () => {
|
|
71
|
+
const { queryByText } = render(PlaylinkTypeSelect, { linkInjection: { ...linkInjection, in_text: true } })
|
|
72
|
+
|
|
73
|
+
expect(queryByText('At least one layout option must be selected for the playlink to be visible.')).not.toBeTruthy()
|
|
74
|
+
})
|
|
63
75
|
})
|
|
@@ -61,9 +61,9 @@ describe('Title.svelte', () => {
|
|
|
61
61
|
})
|
|
62
62
|
|
|
63
63
|
it('Should truncate title when small prop is given', () => {
|
|
64
|
-
const {
|
|
64
|
+
const { getAllByRole } = render(Title, { title, small: true })
|
|
65
65
|
|
|
66
|
-
expect(
|
|
66
|
+
expect(getAllByRole('heading')[0].classList).toContain('truncate')
|
|
67
67
|
})
|
|
68
68
|
|
|
69
69
|
it('Should render given description', () => {
|